[llvm] 16a941e - [VPlan][NFC] Speed up getVectorLoopRegion() with a last-successor walk (#199437)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 22:23:32 PDT 2026


Author: Madhur Amilkanthwar
Date: 2026-08-06T10:53:27+05:30
New Revision: 16a941ef3c157c5f958962d5f72e8f0ee9133001

URL: https://github.com/llvm/llvm-project/commit/16a941ef3c157c5f958962d5f72e8f0ee9133001
DIFF: https://github.com/llvm/llvm-project/commit/16a941ef3c157c5f958962d5f72e8f0ee9133001.diff

LOG: [VPlan][NFC] Speed up getVectorLoopRegion() with a last-successor walk (#199437)

Resolves the TODO in VPlan::getVectorLoopRegion() with a mutable cache
on VPlan, shared by both overloads.

Measured on an O3 build of the LLVM test suite (~12k TUs): 3,556,267
hits / 126,196 misses (96.57% hit rate).

Added: 
    

Modified: 
    llvm/lib/Transforms/Vectorize/VPlan.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp
index 033b00cf03a8b..579ba09855c04 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp
@@ -1074,20 +1074,44 @@ InstructionCost VPlan::cost(ElementCount VF, VPCostContext &Ctx) {
   return Cost;
 }
 
-VPRegionBlock *VPlan::getVectorLoopRegion() {
-  // TODO: Cache if possible.
-  for (VPBlockBase *B : vp_depth_first_shallow(getEntry()))
+// Find the vector loop region by following the last successor of each block,
+// starting from the plan's entry. The vector code path is always the last
+// successor of the entry (and of the min-iters bypass block, if present), and
+// every block on the path to the region has a single predecessor. Stop at the
+// first block with multiple predecessors: in a plain CFG that is the loop
+// header (no region exists yet), and in a rolled CFG it is the middle block
+// following the region.
+static VPRegionBlock *findVectorLoopRegion(VPBlockBase *Entry) {
+  for (VPBlockBase *B = Entry; B && B->getNumPredecessors() <= 1;
+       B = B->hasSuccessors() ? B->getSuccessors().back() : nullptr)
     if (auto *R = dyn_cast<VPRegionBlock>(B))
       return R->isReplicator() ? nullptr : R;
   return nullptr;
 }
 
-const VPRegionBlock *VPlan::getVectorLoopRegion() const {
-  for (const VPBlockBase *B : vp_depth_first_shallow(getEntry()))
+#ifdef EXPENSIVE_CHECKS
+// Reference lookup that scans every top-level block. Used only to validate
+// findVectorLoopRegion() when the invariants of the last-successor walk change.
+static VPRegionBlock *findVectorLoopRegionByScan(VPBlockBase *Entry) {
+  for (VPBlockBase *B : vp_depth_first_shallow(Entry))
     if (auto *R = dyn_cast<VPRegionBlock>(B))
       return R->isReplicator() ? nullptr : R;
   return nullptr;
 }
+#endif
+
+VPRegionBlock *VPlan::getVectorLoopRegion() {
+  VPRegionBlock *LoopRegion = findVectorLoopRegion(getEntry());
+#ifdef EXPENSIVE_CHECKS
+  assert(LoopRegion == findVectorLoopRegionByScan(getEntry()) &&
+         "fast vector loop region lookup disagrees with full CFG scan");
+#endif
+  return LoopRegion;
+}
+
+const VPRegionBlock *VPlan::getVectorLoopRegion() const {
+  return const_cast<VPlan *>(this)->getVectorLoopRegion();
+}
 
 bool VPlan::isOuterLoop() const {
   const VPRegionBlock *LoopRegion = getVectorLoopRegion();


        


More information about the llvm-commits mailing list