[llvm] Extending LoopVersioningLICM to handle cases where loopbound is invariant (PR #192902)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 02:14:50 PDT 2026


================
@@ -213,12 +232,124 @@ bool LoopVersioningLICM::legalLoopStructure() {
   // to generate the bound checks.
   const SCEV *ExitCount = SE->getBackedgeTakenCount(CurLoop);
   if (isa<SCEVCouldNotCompute>(ExitCount)) {
+    IsDynamicBound = true;
     LLVM_DEBUG(dbgs() << "    loop does not have trip count\n");
+    LLVM_DEBUG(dbgs() << "    checking the possibility of dynamic trip count\n");
+
+    HoistedDependencies.clear();
+
+    // Check if the loop trip count is dynamic
+    BasicBlock *ExitBlock = CurLoop->getExitingBlock();
+    assert(ExitBlock && "Exiting block guaranteed by earlier getExitingBlock() check");
+    CondBrInst *ExitBranch = dyn_cast<CondBrInst>(ExitBlock->getTerminator());
+    if (!ExitBranch) {
+      LLVM_DEBUG(dbgs() << "    loop exit condition is not a conditional branch\n");
+      return false;
+    }
+    ICmpInst *ExitCmp = dyn_cast<ICmpInst>(ExitBranch->getCondition());
+    if (!ExitCmp) {
+      LLVM_DEBUG(dbgs() << "    loop exit condition is not an icmp instruction\n");
+      return false;
+    }
+    
+    PHINode *IndVar = CurLoop->getInductionVariable(*SE);
+    if (!IndVar) {
+      LLVM_DEBUG(dbgs() << "    unable to find loop induction variable\n");
+      return false;
+    }
+    LLVM_DEBUG(dbgs() << "    Induction variable: " << *IndVar << "\n");
+
+    Value *StepInst = IndVar->getIncomingValueForBlock(CurLoop->getLoopLatch());
+
+    auto IsIVOrStep = [&](Value *V) {
+      return V == IndVar || V == StepInst;
+    };
+
+    Value *DynamicUpperBound = nullptr;
+    if (IsIVOrStep(ExitCmp->getOperand(0))) {
+      DynamicUpperBound = ExitCmp->getOperand(1);
+    }
+    else if (IsIVOrStep(ExitCmp->getOperand(1))) {
+      DynamicUpperBound = ExitCmp->getOperand(0);
+    }
+    else {
+      LLVM_DEBUG(dbgs() << "    unable to identify dynamic bound operand\n");
+      return false;
+    }
+    LLVM_DEBUG(dbgs() << "    Dynamic upper bound: " << *DynamicUpperBound
+                      << "\n");
+    
+    SmallVector<Instruction *, 16> Worklist;
+    
+    SmallPtrSet<Value *, 16> ModifiedPtrs;
+    for (BasicBlock *BB : CurLoop->getBlocks()) {
+      for (Instruction &I : *BB) {
+        if (StoreInst *SI = dyn_cast<StoreInst>(&I))
+          ModifiedPtrs.insert(SI->getPointerOperand());
+      }
+    }
+
+    if (Instruction *I = dyn_cast<Instruction>(DynamicUpperBound)) {
+      Worklist.push_back(I);
+    }
+    
+    SmallPtrSet<Instruction *, 16> Visited;
+
+    while(!Worklist.empty()) {
+      Instruction *I = Worklist.pop_back_val();
+      if (!Visited.insert(I).second)
+        continue;
+
+      if (!CurLoop->contains(I->getParent()))
+        continue;
+
+      if (!isSafeToHoistBoundDep(I, ModifiedPtrs))
+        return false;
+
+      for (Use &U : I->operands()) {
+        if (Instruction *OpI = dyn_cast<Instruction>(U.get())) {
+          if (CurLoop->contains(OpI)) {
+            Worklist.push_back(OpI);
+          }
+        }
+      }
+
+      HoistedDependencies.push_back(I);
+    }
+    return true;
----------------
artagnon wrote:

```suggestion
```

There's already a `return true` at the end?

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


More information about the llvm-commits mailing list