[llvm] [IR] Use iteration limit in stripPointerCastsAndOffsets (PR #190472)

via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 4 09:20:54 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Alexis Engelke (aengelke)

<details>
<summary>Changes</summary>

Using a SmallPtrSet is not quite free for such a frequently called
operation. However, calls on ill-formed IR are not particularly rare, so
some iteration limit is needed. Therefore, use a simple counter.

Termination statistics on a Clang Release build for N>5:

   2448 N=6
   1295 N=7
    480 N=8
    294 N=9
    160 N=10
  14350 (endless loop)

Therefore, bound the number of iterations by 12, which should cover most
practically relevant cases.

It is worth noting that _all_ of the endless loop cases have the
following form:

  %incdec.ptr = getelementptr inbounds nuw i8, ptr %incdec.ptr, i64 <N>

I haven't investigated where exactly this comes from, though; but it
occurred frequent enough to add a special case for this.


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


1 Files Affected:

- (modified) llvm/lib/IR/Value.cpp (+12-7) 


``````````diff
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 360bf0f8fc47f..d97eb406d2130 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -642,11 +642,12 @@ static const Value *stripPointerCastsAndOffsets(
     return V;
 
   // Even though we don't look through PHI nodes, we could be called on an
-  // instruction in an unreachable block, which may be on a cycle.
-  SmallPtrSet<const Value *, 4> Visited;
-
-  Visited.insert(V);
-  do {
+  // instruction in an unreachable block, which may be on a cycle. E.g.:
+  //   %gep = getelementptr inbounds nuw i8, ptr %gep, i64 32
+  //
+  // Bound against that case with a simple iteration counter. Practically, more
+  // than 10 iterations are almost never needed.
+  for (unsigned N = 0; N < 12; ++N) {
     Func(V);
     if (auto *GEP = dyn_cast<GEPOperator>(V)) {
       switch (StripKind) {
@@ -666,7 +667,11 @@ static const Value *stripPointerCastsAndOffsets(
           return V;
         break;
       }
-      V = GEP->getPointerOperand();
+      const Value *NewV = GEP->getPointerOperand();
+      // Quick exit for degenerate IR, which can happen in unreachable blocks.
+      if (NewV == V)
+        return V;
+      V = NewV;
     } else if (Operator::getOpcode(V) == Instruction::BitCast) {
       Value *NewV = cast<Operator>(V)->getOperand(0);
       if (!NewV->getType()->isPointerTy())
@@ -701,7 +706,7 @@ static const Value *stripPointerCastsAndOffsets(
       return V;
     }
     assert(V->getType()->isPointerTy() && "Unexpected operand type!");
-  } while (Visited.insert(V).second);
+  }
 
   return V;
 }

``````````

</details>


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


More information about the llvm-commits mailing list