[llvm] [LoopUtils] prevent negative estimated trip count result (PR #195610)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 4 01:32:27 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Arda Serdar Pektezol (pektezol)

<details>
<summary>Changes</summary>

`getLoopEstimatedTripCount` will return nullopt whenever the `llvm.loop.estimated_trip_count` is set to 0, but not for negative values. The linked issue contains `AlreadyPeeled` count of 1, with the `llvm.loop.estimated_trip_count` set to -1 in the metadata -- causing the `if (*EstimatedTripCount + AlreadyPeeled <= MaxPeelCount)` case in `LoopPeel` to trigger. After triggering, it peels for INT_MAX which causes the current hang with `opt`.

Fixes #<!-- -->173169


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


2 Files Affected:

- (modified) llvm/lib/Transforms/Utils/LoopUtils.cpp (+3-3) 
- (added) llvm/test/Transforms/LoopUnroll/negative-trip-count.ll (+33) 


``````````diff
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index 03b693974e5fe..d513ef657ba38 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -937,14 +937,14 @@ llvm::getLoopEstimatedTripCount(Loop *L,
   // reached, it is the start of an iteration.  Consequently, some passes
   // historically assume that llvm::getLoopEstimatedTripCount always returns a
   // positive count or std::nullopt.  Thus, return std::nullopt when
-  // llvm.loop.estimated_trip_count is 0.
+  // llvm.loop.estimated_trip_count is 0 or negative.
   if (auto TC = getOptionalIntLoopAttribute(L, LLVMLoopEstimatedTripCount)) {
     LLVM_DEBUG(dbgs() << "getLoopEstimatedTripCount: "
                       << LLVMLoopEstimatedTripCount << " metadata has trip "
                       << "count of " << *TC
-                      << (*TC == 0 ? " (returning std::nullopt)" : "")
+                      << (*TC <= 0 ? " (returning std::nullopt)" : "")
                       << " for " << DbgLoop(L) << "\n");
-    return *TC == 0 ? std::nullopt : std::optional(*TC);
+    return *TC <= 0 ? std::nullopt : std::optional(*TC);
   }
 
   // Estimate the trip count from latch branch weights.
diff --git a/llvm/test/Transforms/LoopUnroll/negative-trip-count.ll b/llvm/test/Transforms/LoopUnroll/negative-trip-count.ll
new file mode 100644
index 0000000000000..d02975ad5dde1
--- /dev/null
+++ b/llvm/test/Transforms/LoopUnroll/negative-trip-count.ll
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=loop-unroll -S < %s | FileCheck %s
+
+define void @PR173169() !prof !0 {
+; CHECK-LABEL: define void @PR173169(
+; CHECK-SAME: ) !prof [[PROF0:![0-9]+]] {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    br i1 true, label %[[LOOP]], label %[[EXIT:.*]], !llvm.loop [[LOOP1:![0-9]+]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:                                             ; preds = %loop, %entry
+  br i1 true, label %loop, label %exit, !llvm.loop !1
+
+exit:                                             ; preds = %loop
+  ret void
+}
+
+!0 = !{!"function_entry_count", i64 1000}
+!1 = distinct !{!1, !2, !3}
+!2 = !{!"llvm.loop.peeled.count", i32 1}
+!3 = !{!"llvm.loop.estimated_trip_count", i32 -1}
+;.
+; CHECK: [[PROF0]] = !{!"function_entry_count", i64 1000}
+; CHECK: [[LOOP1]] = distinct !{[[LOOP1]], [[META2:![0-9]+]], [[META3:![0-9]+]]}
+; CHECK: [[META2]] = !{!"llvm.loop.peeled.count", i32 1}
+; CHECK: [[META3]] = !{!"llvm.loop.estimated_trip_count", i32 -1}
+;.

``````````

</details>


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


More information about the llvm-commits mailing list