[llvm] [LoopInterchange] Don't consider loops with BTC=0 (PR #167113)

Sjoerd Meijer via llvm-commits llvm-commits at lists.llvm.org
Sat Nov 8 01:20:24 PST 2025


https://github.com/sjoerdmeijer created https://github.com/llvm/llvm-project/pull/167113

Do not consider loops with a zero backedge taken count as candidates for interchange. This seems like a sensible thing to do to me, because it suggests the loop doesn't execute and there is no point in interchanging.

This avoids triggering an assert about phis and their uses. I have a feeling that this fix might be hiding the issue, but I haven't yet been able to trigger the assert with other test cases; every time the loops are rejected for other reasons.

Since I think this is a self-contained improvement that avoids a lot of test failures, I propose to reject this loops while I investigate further if I can still trigger this in some way.

(Partial) fix for #163954

>From 899d66b2d3422900c6a9d74164fd770a27b302dc Mon Sep 17 00:00:00 2001
From: Sjoerd Meijer <smeijer at nvidia.com>
Date: Fri, 7 Nov 2025 06:23:51 -0800
Subject: [PATCH] [LoopInterchange] Don't consider loops with BTC=0

Do not consider loops with a zero backedge taken count as candidates for
interchange. This seems like a sensible thing to do to me, because it
suggests the loop doesn't execute and there is no point in
interchanging.

This avoids triggering an assert about phis and their uses. I have a
feeling that this fix might be hiding the issue, but I haven't yet been
able to trigger the assert with other test cases; every time the loops
are rejected for other reasons.

Since I think this is a self-contained improvement that avoids a lot
of test failures, I propose to reject this loops while I investigate
further if I can still trigger this in some way.

(Partial) fix for #163954
---
 llvm/lib/Transforms/Scalar/LoopInterchange.cpp     | 14 ++++++++++++++
 .../LoopInterchange/interchanged-loop-nest-4.ll    |  2 +-
 .../LoopInterchange/lcssa-phi-outer-latch.ll       |  2 +-
 .../LoopInterchange/pr43176-move-to-new-latch.ll   |  2 +-
 llvm/test/Transforms/LoopInterchange/pr43326.ll    |  2 +-
 llvm/test/Transforms/LoopInterchange/pr57148.ll    |  2 +-
 .../reductions-across-inner-and-outer-loop.ll      |  2 +-
 7 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
index 9aaf6a5aa4d6a..11e1723eb03d9 100644
--- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp
@@ -101,6 +101,12 @@ static cl::opt<unsigned int> MaxLoopNestDepth(
     "loop-interchange-max-loop-nest-depth", cl::init(10), cl::Hidden,
     cl::desc("Maximum depth of loop nest considered for the transform"));
 
+// This is mainly for testing purposes, and certain tests that rely on
+// behaviour that is more difficult to trigger otherwise.
+static cl::opt<bool> SkipLoopsWithZeroBTC(
+    "loop-interchange-skip-zero-btc", cl::init(true), cl::Hidden,
+    cl::desc("Do not consider loops with a backedge taken count of 0"));
+
 // We prefer cache cost to vectorization by default.
 static cl::list<RuleTy> Profitabilities(
     "loop-interchange-profitabilities", cl::ZeroOrMore,
@@ -428,6 +434,13 @@ static bool isComputableLoopNest(ScalarEvolution *SE,
       LLVM_DEBUG(dbgs() << "Couldn't compute backedge count\n");
       return false;
     }
+    // A loop with a backedge that isn't taken, e.g. an unconditional branch
+    // true, isn't really a loop and we don't want to consider it as a
+    // candidate.
+    if (ExitCountOuter && SkipLoopsWithZeroBTC && ExitCountOuter->isZero()) {
+      LLVM_DEBUG(dbgs() << "Single iteration loop\n");
+      return false;
+    }
     if (L->getNumBackEdges() != 1) {
       LLVM_DEBUG(dbgs() << "NumBackEdges is not equal to 1\n");
       return false;
@@ -1808,6 +1821,7 @@ static void moveLCSSAPhis(BasicBlock *InnerExit, BasicBlock *InnerHeader,
 
     assert(all_of(P.users(),
                   [OuterHeader, OuterExit, IncI, InnerHeader](User *U) {
+		  dbgs() << "USER: "; U->dump();
                     return (cast<PHINode>(U)->getParent() == OuterHeader &&
                             IncI->getParent() == InnerHeader) ||
                            cast<PHINode>(U)->getParent() == OuterExit;
diff --git a/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll b/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll
index 70fff161154d8..a4dbd5a005082 100644
--- a/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll
+++ b/llvm/test/Transforms/LoopInterchange/interchanged-loop-nest-4.ll
@@ -1,5 +1,5 @@
 ; REQUIRES: asserts
-; RUN: opt < %s -passes="loop(loop-interchange,loop-interchange)" -cache-line-size=8 -verify-dom-info -verify-loop-info \
+; RUN: opt < %s -passes="loop(loop-interchange,loop-interchange)" -cache-line-size=8 -verify-dom-info -verify-loop-info -loop-interchange-skip-zero-btc=false \
 ; RUN:  -debug-only=loop-interchange 2>&1 | FileCheck %s
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll b/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll
index a5e3accaf8e10..ec02110c90e3b 100644
--- a/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll
+++ b/llvm/test/Transforms/LoopInterchange/lcssa-phi-outer-latch.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -verify-dom-info -verify-loop-info -verify-scev -verify-loop-lcssa -S | FileCheck %s
+; RUN: opt < %s -passes=loop-interchange -loop-interchange-skip-zero-btc=false -cache-line-size=64 -verify-dom-info -verify-loop-info -verify-scev -verify-loop-lcssa -S | FileCheck %s
 
 ; This test is checking that blocks outer.body and outer.latch, where outer.body is the exit
 ; block of the inner loop and outer.latch the latch of the outer loop, correctly
diff --git a/llvm/test/Transforms/LoopInterchange/pr43176-move-to-new-latch.ll b/llvm/test/Transforms/LoopInterchange/pr43176-move-to-new-latch.ll
index 6b25c3bc9a4ba..56140236825b7 100644
--- a/llvm/test/Transforms/LoopInterchange/pr43176-move-to-new-latch.ll
+++ b/llvm/test/Transforms/LoopInterchange/pr43176-move-to-new-latch.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -S
+; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -loop-interchange-skip-zero-btc=false -S
 ; RUN: FileCheck --input-file=%t %s
 
 @b = external dso_local global [5 x i32], align 16
diff --git a/llvm/test/Transforms/LoopInterchange/pr43326.ll b/llvm/test/Transforms/LoopInterchange/pr43326.ll
index c25c4fadd3042..8ce3d59e3420f 100644
--- a/llvm/test/Transforms/LoopInterchange/pr43326.ll
+++ b/llvm/test/Transforms/LoopInterchange/pr43326.ll
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -S \
-; RUN:     -verify-dom-info -verify-loop-info -verify-loop-lcssa -stats 2>&1
+; RUN:     -loop-interchange-skip-zero-btc=false -verify-dom-info -verify-loop-info -verify-loop-lcssa -stats 2>&1
 ; RUN: FileCheck --input-file=%t --check-prefix=REMARKS %s
 
 @a = global i32 0
diff --git a/llvm/test/Transforms/LoopInterchange/pr57148.ll b/llvm/test/Transforms/LoopInterchange/pr57148.ll
index 0d4194762a692..51cad15964ed4 100644
--- a/llvm/test/Transforms/LoopInterchange/pr57148.ll
+++ b/llvm/test/Transforms/LoopInterchange/pr57148.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=loop-interchange -cache-line-size=4 -loop-interchange-threshold=-100 -verify-dom-info -verify-loop-info -verify-scev -verify-loop-lcssa -S | FileCheck %s
+; RUN: opt < %s -passes=loop-interchange -loop-interchange-skip-zero-btc=false -cache-line-size=4 -loop-interchange-threshold=-100 -verify-dom-info -verify-loop-info -verify-scev -verify-loop-lcssa -S | FileCheck %s
 
 ; Make sure the loops are in LCSSA form after loop interchange,
 ; and loop interchange does not hit assertion errors and crash.
diff --git a/llvm/test/Transforms/LoopInterchange/reductions-across-inner-and-outer-loop.ll b/llvm/test/Transforms/LoopInterchange/reductions-across-inner-and-outer-loop.ll
index 27d99e05e84ee..fad6a6e70037c 100644
--- a/llvm/test/Transforms/LoopInterchange/reductions-across-inner-and-outer-loop.ll
+++ b/llvm/test/Transforms/LoopInterchange/reductions-across-inner-and-outer-loop.ll
@@ -1,5 +1,5 @@
 ; RUN: opt < %s -passes=loop-interchange -cache-line-size=64 -pass-remarks-missed='loop-interchange' -pass-remarks-output=%t -S \
-; RUN:     -verify-dom-info -verify-loop-info -verify-loop-lcssa -stats 2>&1 | FileCheck %s
+; RUN:     -loop-interchange-skip-zero-btc=false -verify-dom-info -verify-loop-info -verify-loop-lcssa -stats 2>&1 | FileCheck %s
 ; RUN: FileCheck --input-file=%t --check-prefix=REMARKS %s
 
 



More information about the llvm-commits mailing list