[llvm] [LoopVectorize] Enable vectorization of uncountable loops with invariant bound loads via speculative hoisting and runtime versioning. (PR #195027)

Ashutosh Nema via llvm-commits llvm-commits at lists.llvm.org
Thu May 7 10:42:56 PDT 2026


================
@@ -8163,6 +8164,201 @@ static void connectEpilogueVectorLoop(VPlan &EpiPlan, Loop *L,
       Phi.eraseFromParent();
 }
 
+// Is profitable to generate runtime check dominated version of the loop? which
+// has speculatively hoisted the loop bound load.
+static bool isSpeculativeBoundVersioningProfitable() { return true; }
+
+/*
+
+              preheader
+                |
+              rtcheck-block
+                /  \
+               /    \
+        for.preheader    ver.preheader
+            |               |
+         for.body       ver.for.body
+
+*/
+static Loop *tryToVersionLoopForInvariantBoundLoad(
+    Loop *L, LoadInst *BoundLoad, const DataLayout &DL, DominatorTree &DT,
+    LoopInfo &LI, AAResults &AA, PredicatedScalarEvolution &PSE,
+    AssumptionCache *AC) {
+  LoadInst *InnerLoad = BoundLoad;
+  if (!InnerLoad)
+    return nullptr;
+  auto *PreHeader = L->getLoopPreheader();
+  if (!PreHeader)
+    return nullptr;
+
+  Value *BoundPtrOl = InnerLoad->getPointerOperand();
+  if (auto *BoundPtrI = dyn_cast<Instruction>(BoundPtrOl))
+    if (!DT.properlyDominates(BoundPtrI->getParent(), PreHeader))
+      return nullptr;
+
+  // All the relevent base pointers of participating stores should dominate both
+  // loops.
+  LoopAccessInfoManager PreFlightLAIs(*PSE.getSE(), AA, DT, LI, nullptr,
+                                      nullptr, AC);
+  const LoopAccessInfo &PreLAI = PreFlightLAIs.getInfo(*L);
+  const auto &RtPtrChecking = *PreLAI.getRuntimePointerChecking();
+
+  for (const auto &Check : RtPtrChecking.getChecks()) {
+    for (const RuntimeCheckingPtrGroup *Group : {Check.first, Check.second}) {
+      for (unsigned Idx : Group->Members) {
+        Value *Ptr = RtPtrChecking.Pointers[Idx].PointerValue;
+        Value *Base = getUnderlyingObject(Ptr);
+        if (auto *BaseI = dyn_cast<Instruction>(Base))
+          if (!DT.properlyDominates(BaseI->getParent(), PreHeader)) {
+            return nullptr;
+          }
+      }
+    }
+  }
+
+  Function *ParentF = PreHeader->getParent();
+  LLVMContext &Ctx = ParentF->getContext();
+
+  BasicBlock *RtCheckBB =
+      BasicBlock::Create(Ctx, "ivbound.rtcheck", ParentF, PreHeader);
+
+  // Temporary terminator for SCEVExapnder to have valid insert point.
+  IRBuilder<> TmpBuilder(RtCheckBB);
+  Instruction *TmpTerm = TmpBuilder.CreateUnreachable();
+
+  // Re-wire the CFG.
+  // Redirect the predecessors of preheader the new rtcheck block.
+  SmallVector<BasicBlock *, 4> PreHeaderPreds(predecessors(PreHeader));
+  for (auto *Pred : PreHeaderPreds)
+    Pred->getTerminator()->replaceUsesOfWith(PreHeader, RtCheckBB);
+
+  BasicBlock *OldPreheadIdom = DT.getNode(PreHeader)->getIDom()->getBlock();
+  DT.addNewBlock(RtCheckBB, OldPreheadIdom);
+  DT.changeImmediateDominator(PreHeader, RtCheckBB);
+
+  // Fix the preheader phis via rtcblock phis.
+  for (PHINode &PN : make_early_inc_range(PreHeader->phis())) {
+    PHINode *RtcPN =
+        PHINode::Create(PN.getType(), PreHeaderPreds.size(),
+                        PN.getName() + ".rtcphi", RtCheckBB->begin());
+    for (unsigned i = 0; i < PN.getNumIncomingValues(); i++) {
+      BasicBlock *IBB = PN.getIncomingBlock(i);
+      assert(is_contained(PreHeaderPreds, IBB) &&
+             "Incoming Basic Block not part of predecessors list!");
+      RtcPN->addIncoming(PN.getIncomingValue(i), IBB);
+    }
+    PN.replaceAllUsesWith(RtcPN);
+    PN.eraseFromParent();
+  }
+
+  // Clone the loop including preheader.
+  ValueToValueMapTy VMap;
+  SmallVector<BasicBlock *, 4> NewBlocks;
+  Loop *VerLoop = cloneLoopWithPreheader(PreHeader, RtCheckBB, L, VMap, ".lver",
+                                         &LI, &DT, NewBlocks);
+
+  remapInstructionsInBlocks(NewBlocks, VMap);
+
+  BasicBlock *VerPreHeader = cast<BasicBlock>(VMap[PreHeader]);
+  BasicBlock *VerLatch = cast<BasicBlock>(VMap[L->getLoopLatch()]);
+
+  if (Loop *ParLoop = L->getParentLoop())
+    ParLoop->addBasicBlockToLoop(RtCheckBB, LI);
+
+  VerLatch->getTerminator()->setMetadata(LLVMContext::MD_loop, nullptr);
+
+  LoadInst *HoistLoad = cast<LoadInst>(InnerLoad->clone());
+  HoistLoad->setName(InnerLoad->getName() + ".speculatively.hoisted");
+  // Put this hoisted load in RtcheckBB, since SCEVExapnder needs it.
+  HoistLoad->insertBefore(TmpTerm->getIterator());
+  Instruction *ClonedInnerLoad = cast<Instruction>(VMap[InnerLoad]);
+  ClonedInnerLoad->replaceAllUsesWith(HoistLoad);
+  ClonedInnerLoad->eraseFromParent();
+
+  // fix lcssa phis.
+  SmallVector<BasicBlock *, 4> ExitBlocks;
+  L->getExitBlocks(ExitBlocks);
+  for (BasicBlock *ExBB : ExitBlocks) {
+    DT.changeImmediateDominator(ExBB, RtCheckBB);
+    for (PHINode &Phi : ExBB->phis()) {
+      int idx = Phi.getBasicBlockIndex(L->getLoopLatch());
+      if (idx < 0)
+        continue;
+      Value *OrigVal = Phi.getIncomingValue(idx);
+      Value *NewVal =
+          VMap.count(OrigVal) ? cast<Value>(VMap[OrigVal]) : OrigVal;
+      Phi.addIncoming(NewVal, VerLatch);
+    }
+  }
+
+  formDedicatedExitBlocks(L, &DT, &LI, nullptr, true);
+  formDedicatedExitBlocks(VerLoop, &DT, &LI, nullptr, true);
+
+  // RTC condition generation using SCEV.
+  auto &SE = *PSE.getSE();
+  LoopAccessInfoManager NewLAIs(SE, AA, DT, LI, nullptr, nullptr, AC);
+  const LoopAccessInfo &VerLAI = NewLAIs.getInfo(*VerLoop);
+
+  // Generate LAA based ptr runtime checks.
+  SCEVExpander MemExp(*VerLAI.getRuntimePointerChecking()->getSE(),
+                      "ivbound.mem.check");
+  Value *MemRTC = nullptr;
+  if (VerLAI.getRuntimePointerChecking()->Need)
----------------
nema-ashutosh wrote:

We always expect the Need to insert a runtime check should be TRUE here, as we already performed versioning.

It should be an assertion, instead of if condition.

https://github.com/llvm/llvm-project/pull/195027


More information about the llvm-commits mailing list