[llvm] [SCEV] Fix infinite recursion in getZeroExtendExpr via missing Depth propagation (PR #184958)

via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 6 06:30:53 PST 2026


https://github.com/dean-mccoppin updated https://github.com/llvm/llvm-project/pull/184958

>From 23d93f38d38e837be049f5e3994fc87eb091b321 Mon Sep 17 00:00:00 2001
From: hshira6 <hshira6 at wgu.edu>
Date: Fri, 6 Mar 2026 01:50:24 -0500
Subject: [PATCH 1/2] [SCEV] Fix infinite recursion in getZeroExtendExpr via
 missing Depth propagation

getZeroExtendExprImpl called getAddExpr with a proper Depth argument, but
getAddExpr called back into getZeroExtendExpr without propagating Depth
(defaulting to 0), defeating the MaxCastDepth recursion guard and causing
a stack overflow when compiling loops with two interacting induction variables.

Fix by passing Depth through all getZeroExtendExpr call sites inside
getAddExpr and the missing sites inside getZeroExtendExprImpl itself
(2^K mul-trunc and umin/umax/umin_seq folding paths).

Fixes https://github.com/llvm/llvm-project/issues/184947
---
 llvm/lib/Analysis/ScalarEvolution.cpp         | 12 +++---
 .../Transforms/LoopStrengthReduce/pr184947.ll | 43 +++++++++++++++++++
 2 files changed, 49 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/Transforms/LoopStrengthReduce/pr184947.ll

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 083988f948069..732a32a7101e4 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1879,8 +1879,8 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
           getTypeSizeInBits(SM->getOperand(1)->getType()) - C->logBase2();
       Type *NewTruncTy = IntegerType::get(getContext(), NewTruncBits);
       return getMulExpr(
-          getZeroExtendExpr(SM->getOperand(0), Ty),
-          getZeroExtendExpr(getTruncateExpr(TruncRHS, NewTruncTy), Ty),
+          getZeroExtendExpr(SM->getOperand(0), Ty, Depth + 1),
+          getZeroExtendExpr(getTruncateExpr(TruncRHS, NewTruncTy), Ty, Depth + 1),
           SCEV::FlagNUW, Depth + 1);
     }
   }
@@ -1891,7 +1891,7 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
     auto *MinMax = cast<SCEVMinMaxExpr>(Op);
     SmallVector<const SCEV *, 4> Operands;
     for (auto *Operand : MinMax->operands())
-      Operands.push_back(getZeroExtendExpr(Operand, Ty));
+      Operands.push_back(getZeroExtendExpr(Operand, Ty, Depth + 1));
     if (isa<SCEVUMinExpr>(MinMax))
       return getUMinExpr(Operands);
     return getUMaxExpr(Operands);
@@ -1902,7 +1902,7 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
     assert(isa<SCEVSequentialUMinExpr>(MinMax) && "Not supported!");
     SmallVector<const SCEV *, 4> Operands;
     for (auto *Operand : MinMax->operands())
-      Operands.push_back(getZeroExtendExpr(Operand, Ty));
+      Operands.push_back(getZeroExtendExpr(Operand, Ty, Depth + 1));
     return getUMinExpr(Operands, /*Sequential*/ true);
   }
 
@@ -2719,11 +2719,11 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
     if (match(B, m_scev_ZExt(m_scev_Add(InnerAdd)))) {
       const SCEV *NarrowA = getTruncateExpr(A, InnerAdd->getType());
       if (NarrowA == getNegativeSCEV(InnerAdd->getOperand(0)) &&
-          getZeroExtendExpr(NarrowA, B->getType()) == A &&
+          getZeroExtendExpr(NarrowA, B->getType(), Depth) == A &&
           hasFlags(StrengthenNoWrapFlags(this, scAddExpr, {NarrowA, InnerAdd},
                                          SCEV::FlagAnyWrap),
                    SCEV::FlagNUW)) {
-        return getZeroExtendExpr(getAddExpr(NarrowA, InnerAdd), B->getType());
+        return getZeroExtendExpr(getAddExpr(NarrowA, InnerAdd, SCEV::FlagAnyWrap, Depth + 1), B->getType(), Depth);
       }
     }
   }
diff --git a/llvm/test/Transforms/LoopStrengthReduce/pr184947.ll b/llvm/test/Transforms/LoopStrengthReduce/pr184947.ll
new file mode 100644
index 0000000000000..10d5bb8ac6289
--- /dev/null
+++ b/llvm/test/Transforms/LoopStrengthReduce/pr184947.ll
@@ -0,0 +1,43 @@
+; RUN: opt -S -passes=loop-reduce < %s | FileCheck %s
+;
+; Make sure loop-reduce doesn't crash with infinite recursion in
+; getZeroExtendExpr via getAddExpr calling getZeroExtendExpr without
+; propagating the depth argument.
+; See https://github.com/llvm/llvm-project/issues/184947
+
+; Corresponds to:
+;   a() {
+;     int b = 0, c = 0;
+;     for (;; a) {
+;       c++;
+;       if (c <= 14) continue;
+;       b++;
+;       if (b <= 45) continue;
+;       return;
+;     }
+;   }
+
+; CHECK-LABEL: @a(
+define void @a() {
+entry:
+  br label %for.body
+
+for.body:
+  %b.0 = phi i32 [ 0, %entry ], [ %b.next, %for.latch ]
+  %c.0 = phi i32 [ 0, %entry ], [ %c.inc, %for.latch ]
+  %c.inc = add i32 %c.0, 1
+  %cmp.c = icmp sle i32 %c.inc, 14
+  br i1 %cmp.c, label %for.latch, label %b.inc.blk
+
+b.inc.blk:
+  %b.inc = add i32 %b.0, 1
+  %cmp.b = icmp sle i32 %b.inc, 45
+  br i1 %cmp.b, label %for.latch, label %return
+
+for.latch:
+  %b.next = phi i32 [ %b.0, %for.body ], [ %b.inc, %b.inc.blk ]
+  br label %for.body
+
+return:
+  ret void
+}

>From a000e3a85dbfe8eaa530788de7f6562f532bf76d Mon Sep 17 00:00:00 2001
From: hshira6 <hshira6 at wgu.edu>
Date: Fri, 6 Mar 2026 09:30:34 -0500
Subject: [PATCH 2/2] [SCEV] Use Depth+1 consistently in getAddExpr ->
 getZeroExtendExpr calls

Per review feedback, use Depth+1 (not Depth) at the two getZeroExtendExpr
call sites in the A + zext(-A + B) folding path in getAddExpr, consistent
with every other recursive call site in this file.
---
 llvm/lib/Analysis/ScalarEvolution.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 732a32a7101e4..71a1cb4301c73 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -2719,11 +2719,11 @@ const SCEV *ScalarEvolution::getAddExpr(SmallVectorImpl<const SCEV *> &Ops,
     if (match(B, m_scev_ZExt(m_scev_Add(InnerAdd)))) {
       const SCEV *NarrowA = getTruncateExpr(A, InnerAdd->getType());
       if (NarrowA == getNegativeSCEV(InnerAdd->getOperand(0)) &&
-          getZeroExtendExpr(NarrowA, B->getType(), Depth) == A &&
+          getZeroExtendExpr(NarrowA, B->getType(), Depth + 1) == A &&
           hasFlags(StrengthenNoWrapFlags(this, scAddExpr, {NarrowA, InnerAdd},
                                          SCEV::FlagAnyWrap),
                    SCEV::FlagNUW)) {
-        return getZeroExtendExpr(getAddExpr(NarrowA, InnerAdd, SCEV::FlagAnyWrap, Depth + 1), B->getType(), Depth);
+        return getZeroExtendExpr(getAddExpr(NarrowA, InnerAdd, SCEV::FlagAnyWrap, Depth + 1), B->getType(), Depth + 1);
       }
     }
   }



More information about the llvm-commits mailing list