[llvm] [LV] Compute SCEV for memcheck before unlinking (PR #160326)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 23 08:36:43 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-vectorizers

Author: Igor Kirillov (igogo-x86)

<details>
<summary>Changes</summary>

When generating runtime memory checks for outer loops, we split blocks and later unlink them, making the memcheck block unreachable. For instructions in unreachable blocks, ScalarEvolution returns an unknown/poison SCEV, which is treated as a constant and thus loop-invariant. The cost model then assumes the check can be hoisted and underestimates its cost. See this code in `GeneratedRTChecks::getCost`:

```
        const SCEV *Cond = SE->getSCEV(MemRuntimeCheckCond);
        if (SE->isLoopInvariant(Cond, OuterLoop)) {
```

Set OuterLoop early in GeneratedRTChecks::create and compute the SCEV for MemRuntimeCheckCond before unlinking, so getCost() sees the cached expression rather than a poison constant.

---
Full diff: https://github.com/llvm/llvm-project/pull/160326.diff


1 Files Affected:

- (modified) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp (+9-2) 


``````````diff
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index ca092dcfcb492..575f45b051cf6 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -1807,6 +1807,10 @@ class GeneratedRTChecks {
     BasicBlock *LoopHeader = L->getHeader();
     BasicBlock *Preheader = L->getLoopPreheader();
 
+    // Outer loop is used as part of later cost calculations (e.g. to
+    // determine if runtime checks are loop-invariant and can be hoisted).
+    OuterLoop = L->getParentLoop();
+
     // Use SplitBlock to create blocks for SCEV & memory runtime checks to
     // ensure the blocks are properly added to LoopInfo & DominatorTree. Those
     // may be used by SCEVExpander. The blocks will be un-linked from their
@@ -1850,6 +1854,11 @@ class GeneratedRTChecks {
       assert(MemRuntimeCheckCond &&
              "no RT checks generated although RtPtrChecking "
              "claimed checks are required");
+      // Compute SCEV while the block is reachable.
+      // After unlinking, SCEV returns unknown/poison (constant -> invariant),
+      // which makes getCost() wrongly discount hoisted checks.
+      if (OuterLoop)
+        PSE.getSE()->getSCEV(MemRuntimeCheckCond);
     }
 
     SCEVExp.eraseDeadInstructions(SCEVCheckCond);
@@ -1889,8 +1898,6 @@ class GeneratedRTChecks {
       LI->removeBlock(SCEVCheckBlock);
     }
 
-    // Outer loop is used as part of the later cost calculations.
-    OuterLoop = L->getParentLoop();
   }
 
   InstructionCost getCost() {

``````````

</details>


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


More information about the llvm-commits mailing list