[llvm] [IVDescriptors] Check for null SE before deference in getMinMaxRecurrence. (PR #195798)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Mon May 4 23:26:07 PDT 2026


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/195798

Some callers don't pass SCEV.

>From 84eff50295d8058699a26e125040ff1c182c03af Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Mon, 4 May 2026 23:23:51 -0700
Subject: [PATCH] [IVDescriptors] Check for null SE before deference in
 getMinMaxRecurrence.

Some callers don't pass SCEV.
---
 llvm/lib/Analysis/IVDescriptors.cpp           |  2 +
 llvm/unittests/Analysis/IVDescriptorsTest.cpp | 45 +++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp
index 96d30fd1b1415..7549e14366d2c 100644
--- a/llvm/lib/Analysis/IVDescriptors.cpp
+++ b/llvm/lib/Analysis/IVDescriptors.cpp
@@ -393,6 +393,8 @@ static RecurrenceDescriptor getMinMaxRecurrence(PHINode *Phi, Loop *TheLoop,
   StoreInst *IntermediateStore = nullptr;
   const SCEV *StorePtrSCEV = nullptr;
   for (StoreInst *SI : Stores) {
+    if (!SE)
+      return {};
     const SCEV *Ptr = SE->getSCEV(SI->getPointerOperand());
     if (!SE->isLoopInvariant(Ptr, TheLoop) ||
         (StorePtrSCEV && StorePtrSCEV != Ptr))
diff --git a/llvm/unittests/Analysis/IVDescriptorsTest.cpp b/llvm/unittests/Analysis/IVDescriptorsTest.cpp
index 400e90d2e52bf..a56f9800fed76 100644
--- a/llvm/unittests/Analysis/IVDescriptorsTest.cpp
+++ b/llvm/unittests/Analysis/IVDescriptorsTest.cpp
@@ -338,3 +338,48 @@ TEST(IVDescriptorsTest, UnsupportedFindLastPhi) {
                          EXPECT_FALSE(IsRdxPhi);
                        });
 }
+
+// Make sure isReductionPHI doesn't crash when SE is not passed to it.
+TEST(IVDescriptorsTest, InvariantStoreNoSCEV) {
+  // Parse the module.
+  LLVMContext Context;
+
+  std::unique_ptr<Module> M = parseIR(Context, R"(
+    define void @smax_with_invariant_store_user(ptr noalias %src, ptr %dst, i64 %n) {
+    entry:
+      br label %loop
+
+    loop:
+      %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+      %max = phi i32 [ 0, %entry ], [ %max.next, %loop ]
+      %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv
+      %l = load i32, ptr %gep.src, align 4
+      %max.next = tail call i32 @llvm.smax.i32(i32 %max, i32 %l)
+      store i32 %max.next, ptr %dst, align 4
+      %iv.next = add i64 %iv, 1
+      %ec = icmp eq i64 %iv, %n
+      br i1 %ec, label %exit, label %loop
+
+    exit:
+      ret void
+    })");
+
+  runWithLoopInfoAndSE(*M, "smax_with_invariant_store_user",
+                       [&](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
+                         Function::iterator FI = F.begin();
+                         // First basic block is entry - skip it.
+                         BasicBlock *Header = &*(++FI);
+                         assert(Header->getName() == "loop");
+                         Loop *L = LI.getLoopFor(Header);
+                         EXPECT_NE(L, nullptr);
+                         BasicBlock::iterator BBI = Header->begin();
+                         ++BBI;
+                         PHINode *Phi = dyn_cast<PHINode>(&*BBI);
+                         EXPECT_NE(Phi, nullptr);
+                         EXPECT_EQ(Phi->getName(), "max");
+                         RecurrenceDescriptor Rdx;
+                         bool IsRdxPhi =
+                             RecurrenceDescriptor::isReductionPHI(Phi, L, Rdx);
+                         EXPECT_FALSE(IsRdxPhi);
+                       });
+}



More information about the llvm-commits mailing list