[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