[llvm] [LoopUnroll] Make optimization remarks more precise (PR #190714)

Justin Fargnoli via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 14 14:49:23 PDT 2026


https://github.com/justinfargnoli updated https://github.com/llvm/llvm-project/pull/190714

>From 1585d62f872b1c1cf77fbd91f4fede1d293d6b85 Mon Sep 17 00:00:00 2001
From: Justin Fargnoli <jfargnoli at nvidia.com>
Date: Mon, 13 Apr 2026 18:34:13 +0000
Subject: [PATCH] [LoopUnroll] Make optimization remarks more precise

 Conflicts:
	llvm/test/Transforms/LoopUnroll/debug-and-remarks.ll
---
 .../llvm/Transforms/Utils/UnrollLoop.h        |   6 +-
 llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp | 162 +++++++++++-------
 llvm/lib/Transforms/Utils/LoopUnroll.cpp      |  17 +-
 .../{debug.ll => debug-and-remarks.ll}        | 119 +++++++++++--
 4 files changed, 222 insertions(+), 82 deletions(-)
 rename llvm/test/Transforms/LoopUnroll/{debug.ll => debug-and-remarks.ll} (82%)

diff --git a/llvm/include/llvm/Transforms/Utils/UnrollLoop.h b/llvm/include/llvm/Transforms/Utils/UnrollLoop.h
index 364908ca1fad5..8c1bacb5795c7 100644
--- a/llvm/include/llvm/Transforms/Utils/UnrollLoop.h
+++ b/llvm/include/llvm/Transforms/Utils/UnrollLoop.h
@@ -161,8 +161,10 @@ class UnrollCostEstimator {
                                const SmallPtrSetImpl<const Value *> &EphValues,
                                unsigned BEInsns);
 
-  /// Whether it is legal to unroll this loop.
-  LLVM_ABI bool canUnroll() const;
+  /// Whether it is legal to unroll this loop. If \p ORE and \p L are provided,
+  /// emit an optimization remark on failure.
+  LLVM_ABI bool canUnroll(OptimizationRemarkEmitter *ORE = nullptr,
+                          const Loop *L = nullptr) const;
 
   uint64_t getRolledLoopSize() const { return LoopSize.getValue(); }
 
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
index 885ae1f6dc02a..0c137e77f9ed3 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -711,20 +711,28 @@ UnrollCostEstimator::UnrollCostEstimator(
     LoopSize = BEInsns + 1;
 }
 
-bool UnrollCostEstimator::canUnroll() const {
+bool UnrollCostEstimator::canUnroll(OptimizationRemarkEmitter *ORE,
+                                    const Loop *L) const {
+  auto ReportCannotUnroll = [&](StringRef Reason) {
+    LLVM_DEBUG(dbgs().indent(1) << "Not unrolling: " << Reason << ".\n");
+    if (ORE && L)
+      ORE->emit([&]() {
+        return OptimizationRemarkMissed(DEBUG_TYPE, "CannotUnrollLoop",
+                                        L->getStartLoc(), L->getHeader())
+               << "unable to unroll loop: " << Reason;
+      });
+  };
+
   if (Convergence == ConvergenceKind::ExtendedLoop) {
-    LLVM_DEBUG(dbgs().indent(1)
-               << "Not unrolling: contains convergent operations.\n");
+    ReportCannotUnroll("contains convergent operations");
     return false;
   }
   if (!LoopSize.isValid()) {
-    LLVM_DEBUG(dbgs().indent(1)
-               << "Not unrolling: loop size could not be computed.\n");
+    ReportCannotUnroll("loop size could not be computed");
     return false;
   }
   if (NotDuplicatable) {
-    LLVM_DEBUG(dbgs().indent(1)
-               << "Not unrolling: contains non-duplicatable instructions.\n");
+    ReportCannotUnroll("contains non-duplicatable instructions");
     return false;
   }
   return true;
@@ -802,7 +810,8 @@ static std::optional<unsigned>
 shouldPragmaUnroll(Loop *L, const UnrollPragmaInfo &PInfo,
                    const unsigned TripMultiple, const unsigned TripCount,
                    unsigned MaxTripCount, const UnrollCostEstimator UCE,
-                   const TargetTransformInfo::UnrollingPreferences &UP) {
+                   const TargetTransformInfo::UnrollingPreferences &UP,
+                   OptimizationRemarkEmitter *ORE) {
 
   // Using unroll pragma
   // 1st priority is unroll count set by "unroll-count" option.
@@ -832,6 +841,15 @@ shouldPragmaUnroll(Loop *L, const UnrollPragmaInfo &PInfo,
                << "Not unrolling with pragma count " << PInfo.PragmaCount
                << ": remainder not allowed, count does not divide trip "
                << "multiple " << TripMultiple << ".\n");
+    ORE->emit([&]() {
+      return OptimizationRemarkAnalysis(DEBUG_TYPE, "PragmaUnrollCountRejected",
+                                        L->getStartLoc(), L->getHeader())
+             << "may be unable to unroll loop with count "
+             << ore::NV("PragmaCount", PInfo.PragmaCount)
+             << ": remainder loop is not allowed and count does not divide "
+                "trip multiple "
+             << ore::NV("TripMultiple", TripMultiple);
+    });
   }
 
   if (PInfo.PragmaFullUnroll) {
@@ -842,6 +860,14 @@ shouldPragmaUnroll(Loop *L, const UnrollPragmaInfo &PInfo,
       if (TripCount > PragmaUnrollFullMaxIterations) {
         LLVM_DEBUG(dbgs().indent(2)
                    << "Won't unroll; trip count is too large.\n");
+        ORE->emit([&]() {
+          return OptimizationRemarkAnalysis(DEBUG_TYPE,
+                                            "PragmaFullUnrollTripCountTooLarge",
+                                            L->getStartLoc(), L->getHeader())
+                 << "may be unable to fully unroll loop: trip count "
+                 << ore::NV("TripCount", TripCount) << " exceeds limit "
+                 << ore::NV("Limit", PragmaUnrollFullMaxIterations);
+        });
         return std::nullopt;
       }
 
@@ -851,6 +877,12 @@ shouldPragmaUnroll(Loop *L, const UnrollPragmaInfo &PInfo,
     }
     LLVM_DEBUG(dbgs().indent(2)
                << "Not fully unrolling: unknown trip count.\n");
+    ORE->emit([&]() {
+      return OptimizationRemarkAnalysis(DEBUG_TYPE,
+                                        "PragmaFullUnrollUnknownTripCount",
+                                        L->getStartLoc(), L->getHeader())
+             << "may be unable to fully unroll loop: trip count is unknown";
+    });
   }
 
   if (PInfo.PragmaEnableUnroll && !TripCount && MaxTripCount &&
@@ -1039,7 +1071,7 @@ void llvm::computeUnrollCount(Loop *L, const TargetTransformInfo &TTI,
   // 2nd priority is unroll count set by pragma.
   LLVM_DEBUG(dbgs().indent(1) << "Trying pragma unroll...\n");
   if (auto UnrollFactor = shouldPragmaUnroll(L, PInfo, TripMultiple, TripCount,
-                                             MaxTripCount, UCE, UP)) {
+                                             MaxTripCount, UCE, UP, ORE)) {
     UP.Count = *UnrollFactor;
 
     if (PInfo.UserUnrollCount || (PInfo.PragmaCount > 0)) {
@@ -1113,43 +1145,10 @@ void llvm::computeUnrollCount(Loop *L, const TargetTransformInfo &TTI,
   LLVM_DEBUG(dbgs().indent(1) << "Trying partial unroll...\n");
   if (auto UnrollFactor = shouldPartialUnroll(LoopSize, TripCount, UCE, UP)) {
     UP.Count = *UnrollFactor;
-
-    if ((PInfo.PragmaFullUnroll || PInfo.PragmaEnableUnroll) && TripCount &&
-        UP.Count != TripCount)
-      ORE->emit([&]() {
-        return OptimizationRemarkMissed(DEBUG_TYPE,
-                                        "FullUnrollAsDirectedTooLarge",
-                                        L->getStartLoc(), L->getHeader())
-               << "unable to fully unroll loop as directed by unroll metadata "
-                  "because unrolled size is too large";
-      });
-
-    if (UP.PartialThreshold != NoThreshold) {
-      if (UP.Count == 0) {
-        if (PInfo.PragmaEnableUnroll)
-          ORE->emit([&]() {
-            return OptimizationRemarkMissed(DEBUG_TYPE,
-                                            "UnrollAsDirectedTooLarge",
-                                            L->getStartLoc(), L->getHeader())
-                   << "unable to unroll loop as directed by "
-                      "llvm.loop.unroll.enable metadata because unrolled size "
-                      "is too large";
-          });
-      }
-    }
     return;
   }
   assert(TripCount == 0 &&
          "All cases when TripCount is constant should be covered here.");
-  if (PInfo.PragmaFullUnroll)
-    ORE->emit([&]() {
-      return OptimizationRemarkMissed(
-                 DEBUG_TYPE, "CantFullUnrollAsDirectedRuntimeTripCount",
-                 L->getStartLoc(), L->getHeader())
-             << "unable to fully unroll loop as directed by "
-                "llvm.loop.unroll.full metadata because loop has a runtime "
-                "trip count";
-    });
 
   // 7th priority is runtime unrolling.
   LLVM_DEBUG(dbgs().indent(1) << "Trying runtime unroll...\n");
@@ -1207,22 +1206,6 @@ void llvm::computeUnrollCount(Loop *L, const TargetTransformInfo &TTI,
                   "multiple, "
                << TripMultiple << ".  Reducing unroll count from " << OrigCount
                << " to " << UP.Count << ".\n");
-
-    using namespace ore;
-
-    if (PInfo.PragmaCount > 0 && !UP.AllowRemainder)
-      ORE->emit([&]() {
-        return OptimizationRemarkMissed(DEBUG_TYPE,
-                                        "DifferentUnrollCountFromDirected",
-                                        L->getStartLoc(), L->getHeader())
-               << "Unable to unroll loop the number of times directed by "
-                  "llvm.loop.unroll.count metadata because remainder loop is "
-                  "restricted (that could be architecture specific or because "
-                  "the loop contains a convergent instruction) and so must "
-                  "have an unroll count that divides the loop trip multiple of "
-               << NV("TripMultiple", TripMultiple) << ".  Unrolling instead "
-               << NV("UnrollCount", UP.Count) << " time(s).";
-      });
   }
 
   if (UP.Count > UP.MaxCount)
@@ -1293,6 +1276,13 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   if (!L->isLoopSimplifyForm()) {
     LLVM_DEBUG(dbgs().indent(1)
                << "Not unrolling loop which is not in loop-simplify form.\n");
+    if (TM & TM_ForcedByUser) {
+      ORE.emit([&]() {
+        return OptimizationRemarkMissed(DEBUG_TYPE, "NotInLoopSimplifyForm",
+                                        L->getStartLoc(), L->getHeader())
+               << "unable to unroll loop: not in loop-simplify form";
+      });
+    }
     return LoopUnrollResult::Unmodified;
   }
 
@@ -1318,6 +1308,13 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   if (UP.Threshold == 0 && (!UP.Partial || UP.PartialThreshold == 0) &&
       !OptForSize) {
     LLVM_DEBUG(dbgs().indent(1) << "Not unrolling: all thresholds are zero.\n");
+    if (TM & TM_ForcedByUser) {
+      ORE.emit([&]() {
+        return OptimizationRemarkMissed(DEBUG_TYPE, "UnrollThresholdsZero",
+                                        L->getStartLoc(), L->getHeader())
+               << "unable to unroll loop: unroll threshold is zero";
+      });
+    }
     return LoopUnrollResult::Unmodified;
   }
 
@@ -1325,7 +1322,7 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   CodeMetrics::collectEphemeralValues(L, &AC, EphValues);
 
   UnrollCostEstimator UCE(L, TTI, EphValues, UP.BEInsns);
-  if (!UCE.canUnroll())
+  if (!UCE.canUnroll((TM & TM_ForcedByUser) ? &ORE : nullptr, L))
     return LoopUnrollResult::Unmodified;
 
   unsigned LoopSize = UCE.getRolledLoopSize();
@@ -1339,6 +1336,14 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   if (UCE.NumInlineCandidates != 0) {
     LLVM_DEBUG(dbgs().indent(1)
                << "Not unrolling loop with inlinable calls.\n");
+    if (TM & TM_ForcedByUser) {
+      ORE.emit([&]() {
+        return OptimizationRemarkMissed(DEBUG_TYPE,
+                                        "InlineCandidatesPreventUnroll",
+                                        L->getStartLoc(), L->getHeader())
+               << "unable to unroll loop: contains inlinable calls";
+      });
+    }
     return LoopUnrollResult::Unmodified;
   }
 
@@ -1392,6 +1397,13 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   if (!UP.Count) {
     LLVM_DEBUG(dbgs().indent(1)
                << "Not unrolling: no viable strategy found.\n");
+    if (TM & TM_ForcedByUser) {
+      ORE.emit([&]() {
+        return OptimizationRemarkMissed(DEBUG_TYPE, "NoUnrollStrategy",
+                                        L->getStartLoc(), L->getHeader())
+               << "unable to unroll loop: no viable unroll count found";
+      });
+    }
     return LoopUnrollResult::Unmodified;
   }
 
@@ -1438,6 +1450,8 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   // Save loop properties before it is transformed.
   MDNode *OrigLoopID = L->getLoopID();
   UnrollPragmaInfo PInfo(L);
+  DebugLoc LoopStartLoc = L->getStartLoc();
+  BasicBlock *LoopHeader = L->getHeader();
 
   // Unroll the loop.
   Loop *RemainderLoop = nullptr;
@@ -1454,8 +1468,36 @@ tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
   ULO.AddAdditionalAccumulators = UP.AddAdditionalAccumulators;
   LoopUnrollResult UnrollResult = UnrollLoop(
       L, ULO, LI, &SE, &DT, &AC, &TTI, &ORE, PreserveLCSSA, &RemainderLoop, AA);
-  if (UnrollResult == LoopUnrollResult::Unmodified)
+  if (UnrollResult == LoopUnrollResult::Unmodified) {
+    if (PInfo.ExplicitUnroll) {
+      LLVM_DEBUG(dbgs().indent(1)
+                 << "Failed to unroll loop as explicitly requested.\n");
+      ORE.emit([&]() {
+        return OptimizationRemarkMissed(DEBUG_TYPE, "FailedToUnrollAsRequested",
+                                        LoopStartLoc, LoopHeader)
+               << "failed to unroll loop as explicitly requested";
+      });
+    }
     return LoopUnrollResult::Unmodified;
+  }
+
+  if (PInfo.PragmaFullUnroll && ULO.Count != TripCount) {
+    ORE.emit([&]() {
+      return OptimizationRemarkMissed(DEBUG_TYPE, "FullUnrollAsDirectedFailed",
+                                      LoopStartLoc, LoopHeader)
+             << "unable to fully unroll loop as directed; "
+             << "unrolled by factor " << ore::NV("UnrollCount", ULO.Count);
+    });
+  }
+  if (PInfo.PragmaCount > 0 && ULO.Count != PInfo.PragmaCount) {
+    ORE.emit([&]() {
+      return OptimizationRemarkMissed(DEBUG_TYPE, "UnrollCountDiffers",
+                                      LoopStartLoc, LoopHeader)
+             << "unable to unroll loop with requested count "
+             << ore::NV("RequestedCount", PInfo.PragmaCount)
+             << "; unrolled by factor " << ore::NV("UnrollCount", ULO.Count);
+    });
+  }
 
   if (RemainderLoop) {
     std::optional<MDNode *> RemainderLoopID =
diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp
index 3094beeb5005c..df93e71c9914c 100644
--- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp
@@ -840,11 +840,15 @@ llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI,
                << NV("UnrollCount", ULO.Count) << " iterations";
       });
   } else {
-    LLVM_DEBUG(dbgs() << "UNROLLING loop %" << Header->getName() << " by "
-                      << ULO.Count);
-    if (ULO.Runtime)
-      LLVM_DEBUG(dbgs() << " with run-time trip count");
-    LLVM_DEBUG(dbgs() << "!\n");
+    LLVM_DEBUG({
+      dbgs() << "UNROLLING loop %" << Header->getName() << " by " << ULO.Count;
+      if (ULO.Runtime) {
+        dbgs() << " with run-time trip count";
+        if (ULO.UnrollRemainder)
+          dbgs() << " (remainder unrolled)";
+      }
+      dbgs() << "!\n";
+    });
 
     if (ORE)
       ORE->emit([&]() {
@@ -852,7 +856,8 @@ llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI,
                                 L->getHeader());
         Diag << "unrolled loop by a factor of " << NV("UnrollCount", ULO.Count);
         if (ULO.Runtime)
-          Diag << " with run-time trip count";
+          Diag << " with run-time trip count"
+               << (ULO.UnrollRemainder ? " (remainder unrolled)" : "");
         return Diag;
       });
   }
diff --git a/llvm/test/Transforms/LoopUnroll/debug.ll b/llvm/test/Transforms/LoopUnroll/debug-and-remarks.ll
similarity index 82%
rename from llvm/test/Transforms/LoopUnroll/debug.ll
rename to llvm/test/Transforms/LoopUnroll/debug-and-remarks.ll
index f3bcdc52db073..3cf92dbbf9315 100644
--- a/llvm/test/Transforms/LoopUnroll/debug.ll
+++ b/llvm/test/Transforms/LoopUnroll/debug-and-remarks.ll
@@ -1,13 +1,37 @@
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-allow-partial < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=PARTIAL-ALLOW
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-count=4 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=USER-COUNT
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-count=9999 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=USER-COUNT-EXCEED
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-peel-count=2 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=EXPLICIT-PEEL
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-threshold=0 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=ZERO-THRESH
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-full-max-count=2 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=MAX-COUNT
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-allow-partial -unroll-partial-threshold=4 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=PARTIAL-NOPROFIT
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-allow-remainder=false < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=PRAGMA-NOREMAINDER
-; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -unroll-partial-threshold=9 < %s 2>&1 | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=RUNTIME-NOPROFIT
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-allow-partial < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=PARTIAL-ALLOW
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-count=4 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=USER-COUNT
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-count=9999 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=USER-COUNT-EXCEED
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-peel-count=2 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=EXPLICIT-PEEL
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-threshold=0 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=ZERO-THRESH
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-full-max-count=2 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=MAX-COUNT
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-allow-partial -unroll-partial-threshold=4 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=PARTIAL-NOPROFIT
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-allow-remainder=false < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=PRAGMA-NOREMAINDER
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-remainder < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=REMAINDER
+; RUN: opt -disable-output -passes=loop-unroll -debug-only=loop-unroll -pass-remarks=loop-unroll \
+; RUN:     -pass-remarks-missed=loop-unroll -pass-remarks-analysis=loop-unroll -unroll-partial-threshold=9 < %s 2>&1 \
+; RUN:     | FileCheck %s --match-full-lines --strict-whitespace --check-prefix=RUNTIME-NOPROFIT
+
 
 ; REQUIRES: asserts
 
@@ -17,6 +41,7 @@
 ; CHECK-NEXT: Explicit unroll requested: pragma-full
 ; CHECK-NEXT: Trying pragma unroll...
 ; CHECK-NEXT:  Not fully unrolling: unknown trip count.
+; CHECK-NEXT:remark: <unknown>:0:0: may be unable to fully unroll loop: trip count is unknown
 ; CHECK-NEXT: Trying full unroll...
 ; CHECK-NEXT: Trying upper-bound unroll...
 ; CHECK-NEXT: Trying loop peeling...
@@ -24,6 +49,7 @@
 ; CHECK-NEXT: Trying runtime unroll...
 ; CHECK-NEXT:  Will not try to unroll loop with runtime trip count because -unroll-runtime not given
 ; CHECK-NEXT: Not unrolling: no viable strategy found.
+; CHECK-NEXT:remark: <unknown>:0:0: unable to unroll loop: no viable unroll count found
 
 define i32 @pragma_full_unroll_unknown_tc(ptr %A, i32 %n) {
 entry:
@@ -78,6 +104,7 @@ exit:
 
 ; CHECK-LABEL:Loop Unroll: F[extended_convergence] Loop %for.body (depth=1)
 ; CHECK-NEXT: Not unrolling: contains convergent operations.
+; CHECK-NEXT:remark: <unknown>:0:0: unable to unroll loop: contains convergent operations
 
 declare void @convergent_func() convergent
 declare token @llvm.experimental.convergence.anchor()
@@ -104,6 +131,7 @@ exit:
 
 ; CHECK-LABEL:Loop Unroll: F[noduplicate_prevents_unroll] Loop %for.body (depth=1)
 ; CHECK-NEXT: Not unrolling: contains non-duplicatable instructions.
+; CHECK-NEXT:remark: <unknown>:0:0: unable to unroll loop: contains non-duplicatable instructions
 
 declare void @noduplicate_func() noduplicate
 
@@ -128,6 +156,7 @@ exit:
 
 ; CHECK-LABEL:Loop Unroll: F[indirectbr_loop] Loop %for.body (depth=1)
 ; CHECK-NEXT: Not unrolling loop which is not in loop-simplify form.
+; CHECK-NEXT:remark: <unknown>:0:0: unable to unroll loop: not in loop-simplify form
 
 define i32 @indirectbr_loop(ptr %A, ptr %target) {
 entry:
@@ -151,6 +180,7 @@ exit:
 ; CHECK-LABEL:Loop Unroll: F[inline_prevents_unroll] Loop %for.body (depth=1)
 ; CHECK-NEXT:Loop Size = 8
 ; CHECK-NEXT: Not unrolling loop with inlinable calls.
+; CHECK-NEXT:remark: <unknown>:0:0: unable to unroll loop: contains inlinable calls
 
 define internal i32 @single_use_helper(i32 %x) {
   %add = add i32 %x, 42
@@ -198,6 +228,7 @@ exit:
 ; CHECK-NEXT:  Profitable after cost analysis.
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=10, TripMultiple=0, BreakoutTrip=0
 ; CHECK-NEXT:COMPLETELY UNROLLING loop %for.body with trip count 10!
+; CHECK-NEXT:remark: <unknown>:0:0: completely unrolled loop with 10 iterations
 
 define i32 @full_unroll_profitability_analysis(ptr %A, ptr %B) {
 entry:
@@ -297,6 +328,7 @@ exit:
 ; CHECK-NEXT:  Unrolling: size {{[0-9]+}} < threshold {{[0-9]+}}.
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=4, TripMultiple=0, BreakoutTrip=0
 ; CHECK-NEXT:COMPLETELY UNROLLING loop %for.body with trip count 4!
+; CHECK-NEXT:remark: <unknown>:0:0: completely unrolled loop with 4 iterations
 
 define i32 @full_unroll_size_under_threshold(ptr %A) {
 entry:
@@ -324,6 +356,7 @@ exit:
 ; CHECK-NEXT:  Fully unrolling with trip count: 6.
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=6, TripMultiple=0, BreakoutTrip=0
 ; CHECK-NEXT:COMPLETELY UNROLLING loop %for.body with trip count 6!
+; CHECK-NEXT:remark: <unknown>:0:0: completely unrolled loop with 6 iterations
 
 define i32 @pragma_full_known_tc(ptr %A) {
 entry:
@@ -351,6 +384,7 @@ exit:
 ; CHECK-NEXT:  Unrolling with pragma count: 3.
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=12, TripMultiple=0, BreakoutTrip=0
 ; CHECK-NEXT:UNROLLING loop %for.body by 3!
+; CHECK-NEXT:remark: <unknown>:0:0: unrolled loop by a factor of 3
 
 define i32 @pragma_count_unroll(ptr %A) {
 entry:
@@ -431,6 +465,7 @@ exit:
 ; CHECK-NEXT:  Unrolling with max trip count: 3.
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=0, TripMultiple=1, BreakoutTrip=1
 ; CHECK-NEXT:COMPLETELY UNROLLING loop %for.body with trip count 3!
+; CHECK-NEXT:remark: <unknown>:0:0: completely unrolled loop with 3 iterations
 
 define i32 @upper_bound_unroll(ptr %A, i32 %n) {
 entry:
@@ -527,6 +562,7 @@ exit:
 ; CHECK-NEXT: Trying loop peeling...
 ; CHECK-NEXT:  Peeling with count: 1.
 ; CHECK-NEXT:PEELING loop %for.header with iteration count 1!
+; CHECK-NEXT:remark: <unknown>:0:0: peeled loop by 1 iterations
 
 declare void @foo()
 
@@ -568,10 +604,22 @@ exit:
 ; CHECK-NEXT:  Runtime unrolling with count: 8
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=0, TripMultiple=1, BreakoutTrip=1
 ; CHECK:UNROLLING loop %for.body by 8 with run-time trip count!
+; CHECK-NEXT:remark: <unknown>:0:0: unrolled loop by a factor of 8 with run-time trip count
 ;
-; With a low partial threshold, the runtime unroll count is reduced below 2
-; and no unrolling occurs. Verify we don't print a misleading
-; "Runtime unrolling with count" message.
+; REMAINDER-LABEL:Loop Unroll: F[runtime_unroll_simple] Loop %for.body (depth=1)
+; REMAINDER-NEXT:Loop Size = 6
+; REMAINDER-NEXT: Computing unroll count: TripCount=0, MaxTripCount=2147483647, TripMultiple=1
+; REMAINDER-NEXT: Explicit unroll requested: pragma-enable
+; REMAINDER-NEXT: Trying pragma unroll...
+; REMAINDER-NEXT: Trying full unroll...
+; REMAINDER-NEXT: Trying upper-bound unroll...
+; REMAINDER-NEXT: Trying loop peeling...
+; REMAINDER-NEXT: Trying partial unroll...
+; REMAINDER-NEXT: Trying runtime unroll...
+; REMAINDER-NEXT:  Runtime unrolling with count: 8
+; REMAINDER-NEXT:  Exiting block %for.body: TripCount=0, TripMultiple=1, BreakoutTrip=1
+; REMAINDER:UNROLLING loop %for.body by 8 with run-time trip count (remainder unrolled)!
+; REMAINDER-NEXT:remark: <unknown>:0:0: unrolled loop by a factor of 8 with run-time trip count (remainder unrolled)
 ;
 ; RUNTIME-NOPROFIT-LABEL:Loop Unroll: F[runtime_unroll_simple] Loop %for.body (depth=1)
 ; RUNTIME-NOPROFIT-NEXT:Loop Size = 6
@@ -620,6 +668,7 @@ exit:
 ; PARTIAL-ALLOW-NEXT:  Partially unrolling with count: {{[0-9]+}}
 ; PARTIAL-ALLOW-NEXT:  Exiting block %for.body: TripCount=200, TripMultiple=0, BreakoutTrip=0
 ; PARTIAL-ALLOW-NEXT:UNROLLING loop %for.body by {{[0-9]+}}!
+; PARTIAL-ALLOW-NEXT:remark: <unknown>:0:0: unrolled loop by a factor of {{[0-9]+}}
 
 define i32 @partial_unroll_cost_analysis(ptr %A) {
 entry:
@@ -645,6 +694,7 @@ exit:
 ; CHECK-NEXT: Explicit unroll requested: pragma-full
 ; CHECK-NEXT: Trying pragma unroll...
 ; CHECK-NEXT:  Won't unroll; trip count is too large.
+; CHECK-NEXT:remark: <unknown>:0:0: may be unable to fully unroll loop: trip count 1000001 exceeds limit 1000000
 ; CHECK-NEXT: Trying full unroll...
 ; CHECK-NEXT:  Unrolled size {{[0-9]+}} exceeds threshold {{[0-9]+}}; checking for cost benefit.
 ; CHECK-NEXT:   Not analyzing loop cost: trip count too large.
@@ -655,6 +705,8 @@ exit:
 ; CHECK-NEXT:  Partially unrolling with count: {{[0-9]+}}
 ; CHECK-NEXT:  Exiting block %for.body: TripCount=1000001, TripMultiple=0, BreakoutTrip=0
 ; CHECK-NEXT:UNROLLING loop %for.body by {{[0-9]+}}!
+; CHECK-NEXT:remark: <unknown>:0:0: unrolled loop by a factor of {{[0-9]+}}
+; CHECK-NEXT:remark: <unknown>:0:0: unable to fully unroll loop as directed; unrolled by factor {{[0-9]+}}
 
 define i32 @pragma_full_tc_too_large(ptr %A) {
 entry:
@@ -747,6 +799,7 @@ exit:
 ; USER-COUNT-NEXT:  Unrolling with user-specified count: 4.
 ; USER-COUNT-NEXT:  Exiting block %for.body: TripCount=12, TripMultiple=0, BreakoutTrip=0
 ; USER-COUNT-NEXT:UNROLLING loop %for.body by 4!
+; USER-COUNT-NEXT:remark: <unknown>:0:0: unrolled loop by a factor of 4
 ;
 ; USER-COUNT-EXCEED-LABEL:Loop Unroll: F[user_count_unroll] Loop %for.body (depth=1)
 ; USER-COUNT-EXCEED-NEXT:Loop Size = 6
@@ -758,6 +811,7 @@ exit:
 ; USER-COUNT-EXCEED-NEXT:  Unrolling: size {{[0-9]+}} < threshold {{[0-9]+}}.
 ; USER-COUNT-EXCEED-NEXT:  Exiting block %for.body: TripCount=12, TripMultiple=0, BreakoutTrip=0
 ; USER-COUNT-EXCEED-NEXT:COMPLETELY UNROLLING loop %for.body with trip count 12!
+; USER-COUNT-EXCEED-NEXT:remark: <unknown>:0:0: completely unrolled loop with 12 iterations
 
 define i32 @user_count_unroll(ptr %A) {
 entry:
@@ -782,6 +836,7 @@ exit:
 ; EXPLICIT-PEEL-NEXT: Computing unroll count: TripCount=0, MaxTripCount=2147483647, TripMultiple=1
 ; EXPLICIT-PEEL-NEXT:  Using explicit peel count: 2.
 ; EXPLICIT-PEEL-NEXT:PEELING loop %for.body with iteration count 2!
+; EXPLICIT-PEEL-NEXT:remark: <unknown>:0:0: peeled loop by 2 iterations
 
 define i32 @explicit_peel_count(ptr %A, i32 %n) {
 entry:
@@ -805,6 +860,7 @@ exit:
 
 ; ZERO-THRESH-LABEL:Loop Unroll: F[zero_thresh_unroll] Loop %for.body (depth=1)
 ; ZERO-THRESH-NEXT: Not unrolling: all thresholds are zero.
+; ZERO-THRESH-NEXT:remark: <unknown>:0:0: unable to unroll loop: unroll threshold is zero
 
 define i32 @zero_thresh_unroll(ptr %A) {
 entry:
@@ -818,7 +874,7 @@ for.body:
   %add = add i32 %sum, %load
   %inc = add i32 %i, 1
   %cmp = icmp ult i32 %inc, 8
-  br i1 %cmp, label %for.body, label %exit
+  br i1 %cmp, label %for.body, label %exit, !llvm.loop !16
 
 exit:
   ret i32 %add
@@ -893,10 +949,13 @@ exit:
 ; PRAGMA-NOREMAINDER-NEXT: Explicit unroll requested: pragma-count(3)
 ; PRAGMA-NOREMAINDER-NEXT: Trying pragma unroll...
 ; PRAGMA-NOREMAINDER-NEXT:  Not unrolling with pragma count 3: remainder not allowed, count does not divide trip multiple 10.
+; PRAGMA-NOREMAINDER-NEXT:remark: <unknown>:0:0: may be unable to unroll loop with count 3: remainder loop is not allowed and count does not divide trip multiple 10
 ; PRAGMA-NOREMAINDER-NEXT: Trying full unroll...
 ; PRAGMA-NOREMAINDER-NEXT:  Unrolling: size {{[0-9]+}} < threshold {{[0-9]+}}.
 ; PRAGMA-NOREMAINDER-NEXT:  Exiting block %for.body: TripCount=10, TripMultiple=0, BreakoutTrip=0
 ; PRAGMA-NOREMAINDER-NEXT:COMPLETELY UNROLLING loop %for.body with trip count 10!
+; PRAGMA-NOREMAINDER-NEXT:remark: <unknown>:0:0: completely unrolled loop with 10 iterations
+; PRAGMA-NOREMAINDER-NEXT:remark: <unknown>:0:0: unable to unroll loop with requested count 3; unrolled by factor 10
 
 define i32 @pragma_count_no_remainder(ptr %A) {
 entry:
@@ -916,6 +975,36 @@ exit:
   ret i32 %add
 }
 
+; CHECK-LABEL:Loop Unroll: F[header_address_taken] Loop %for.body (depth=1)
+; CHECK-NEXT:Loop Size = 6
+; CHECK-NEXT: Computing unroll count: TripCount=4, MaxTripCount=0, TripMultiple=4
+; CHECK-NEXT: Explicit unroll requested: pragma-enable
+; CHECK-NEXT: Trying pragma unroll...
+; CHECK-NEXT: Trying full unroll...
+; CHECK-NEXT:  Unrolling: size {{[0-9]+}} < threshold {{[0-9]+}}.
+; CHECK-NEXT:  Won't unroll loop: address of header block is taken.
+; CHECK-NEXT: Failed to unroll loop as explicitly requested.
+; CHECK-NEXT:remark: <unknown>:0:0: failed to unroll loop as explicitly requested
+
+define i32 @header_address_taken(ptr %A) {
+entry:
+  store ptr blockaddress(@header_address_taken, %for.body), ptr %A
+  br label %for.body
+
+for.body:
+  %i = phi i32 [ 0, %entry ], [ %inc, %for.body ]
+  %sum = phi i32 [ 0, %entry ], [ %add, %for.body ]
+  %arrayidx = getelementptr inbounds i32, ptr %A, i32 %i
+  %load = load i32, ptr %arrayidx
+  %add = add i32 %sum, %load
+  %inc = add i32 %i, 1
+  %cmp = icmp ult i32 %inc, 4
+  br i1 %cmp, label %for.body, label %exit, !llvm.loop !15
+
+exit:
+  ret i32 %add
+}
+
 !0 = distinct !{!0, !3}
 !1 = distinct !{!1, !4}
 !2 = distinct !{!2, !4}
@@ -931,3 +1020,5 @@ exit:
 !12 = distinct !{!12, !3}
 !13 = distinct !{!13, !4}
 !14 = distinct !{!14, !6}
+!15 = distinct !{!15, !4}
+!16 = distinct !{!16, !4}



More information about the llvm-commits mailing list