[llvm] Extending LoopVersioningLICM to handle cases where loopbound is invariant (PR #192902)
Manish Srivastava via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 28 03:34:54 PDT 2026
================
@@ -507,39 +638,149 @@ bool LoopVersioningLICM::isLegalForVersioning() {
return true;
}
+Instruction *LoopVersioningLICM::insertRuntimeCheckPlaceholder(Loop *L) {
+ // Preheader for our checks
+ BasicBlock *Preheader = L->getLoopPreheader();
+
+ // Determine the insertion point.
+ Instruction *InsertPt = Preheader->getTerminator();
+ LLVMContext &Context = CurLoop->getHeader()->getParent()->getContext();
+ // Create the comparison.
+ Instruction *Placeholder = nullptr;
+ Placeholder = ICmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ,
+ ConstantInt::get(Type::getInt32Ty(Context), 1),
+ ConstantInt::get(Type::getInt32Ty(Context), 1),
+ "runtime.check.placeholder", InsertPt->getIterator());
+
+ return Placeholder;
+}
+
+void LoopVersioningLICM::generateAndAddRuntimeChecks(DominatorTree *DT) {
+ BasicBlock *RuntimeCheckBB = PlaceholderForRuntimeChecks->getParent();
+
+ const auto &RtPtrChecking = *LAI->getRuntimePointerChecking();
+
+ SCEVExpander Exp1(*RtPtrChecking.getSE(), "induction");
+
+ auto RPC = LAI->getRuntimePointerChecking();
+
+ Value *MemRuntimeChecks = llvm::addRuntimeChecks(PlaceholderForRuntimeChecks,
+ CurLoop, RPC->getChecks(), Exp1);
+
+ SCEVExpander Exp2(*SE, "scev.check");
+
+ const SCEVPredicate &Preds(LAI->getPSE().getPredicate());
+ Value *SCEVRuntimeChecks = Exp2.expandCodeForPredicate(&Preds, PlaceholderForRuntimeChecks);
+
+ IRBuilder<InstSimplifyFolder> Builder(RuntimeCheckBB->getContext(),
+ InstSimplifyFolder(RuntimeCheckBB->getModule()->getDataLayout()));
+
+ Value *RuntimeCheck = nullptr;
+ if (MemRuntimeChecks && SCEVRuntimeChecks) {
+ Builder.SetInsertPoint(PlaceholderForRuntimeChecks);
+ RuntimeCheck = Builder.CreateOr(MemRuntimeChecks, SCEVRuntimeChecks, "lver.safe");
+ } else {
+ RuntimeCheck = MemRuntimeChecks ? MemRuntimeChecks : SCEVRuntimeChecks;
+ }
+
+ RuntimeCheckBB->setName(CurLoop->getHeader()->getName() + ".lver.check");
+
+ CondBrInst *BI = dyn_cast<CondBrInst>(RuntimeCheckBB->getTerminator());
+ assert(BI && "Expected conditional branch in runtime check block");
+
+ assert(RuntimeCheck && "called even though we don't need "
+ "any runtime checks");
+
+ PlaceholderForRuntimeChecks->replaceAllUsesWith(RuntimeCheck);
+ PlaceholderForRuntimeChecks->eraseFromParent();
+}
+
bool LoopVersioningLICM::run(DominatorTree *DT) {
// Do not do the transformation if disabled by metadata.
if (hasLICMVersioningTransformation(CurLoop) & TM_Disable)
return false;
-
bool Changed = false;
-
// Check feasiblity of LoopVersioningLICM.
// If versioning found to be feasible and beneficial then proceed
// else simply return, by cleaning up memory.
if (isLegalForVersioning()) {
+ PlaceholderForRuntimeChecks = nullptr;
+ if (IsDynamicBound) {
+ PlaceholderForRuntimeChecks = insertRuntimeCheckPlaceholder(CurLoop);
+ if (!PlaceholderForRuntimeChecks) {
+ LLVM_DEBUG(dbgs() << "No runtime check created\n");
+ return false;
+ }
+ }
// Do loop versioning.
// Create memcheck for memory accessed inside loop.
// Clone original loop, and set blocks properly.
LoopVersioning LVer(*LAI, LAI->getRuntimePointerChecking()->getChecks(),
CurLoop, &LI, DT, SE);
- LVer.versionLoop();
+ LVer.versionLoop(PlaceholderForRuntimeChecks);
+
+ // Add the extra checks for dynamic bounds
+ if (IsDynamicBound) {
+ for (auto p = HoistedDependencies.rbegin(); p != HoistedDependencies.rend(); ++p) {
+ Instruction *I = *p;
+ if (isa<LoadInst>(I)) {
+ // Clone the load to the preheader instead of moving it. The original
+ // dead load is intentionally kept in the loop body so that the subsequent LAA recomputation sees
+ // the load and generates runtime pointer checks for its address range. The cleanup passes will erase it later.
+ LoadInst *LI = cast<LoadInst>(I);
+ LoadInst *NewLI = new LoadInst(
+ LI->getType(), LI->getPointerOperand(), LI->getName() + ".hoisted",
+ false, LI->getAlign(), LI->getOrdering(), LI->getSyncScopeID(),
+ PlaceholderForRuntimeChecks->getIterator()
+ );
+
+ NewLI->copyMetadata(*I);
+ I->replaceAllUsesWith(NewLI);
+ } else {
+ I->moveBefore(PlaceholderForRuntimeChecks->getIterator());
+ }
+ }
+
+// #ifdef EXPENSIVE_CHECKS
+ assert(!verifyFunction(*LVer.getVersionedLoop()->getHeader()->getParent(), &dbgs())
+ && "Verification failure after dynamic bounds");
+// #endif
+
+ SE->forgetLoop(CurLoop);
+ // Recompute LoopAccessInfo after hoisting the dynamic bound
+ LoopAccessInfoManager FreshLAIs(*SE, *AA, *DT, LI, nullptr, nullptr, AC);
+ LAI = &FreshLAIs.getInfo(*CurLoop);
----------------
mk-srivastava wrote:
I tried your suggestion but this seems to be introducing some new issues.
Mainly if I try to reuse `LAIs` and call `getInfo` it seems we delete few entries which we still need for further transformations as `LVer` still keeps the earlier deleted entries.
So, a fresh `LoopAccessInfoManager` recomputes the analysis without deleting the object `LVer` still needs for further transformation.
https://github.com/llvm/llvm-project/pull/192902
More information about the llvm-commits
mailing list