[llvm] [VPlan] Guard VPPartialReductionRecipe::computeCost() against ilist sentinel(#148389) (PR #148555)
Shashi Shankar via llvm-commits
llvm-commits at lists.llvm.org
Sun Jul 13 16:21:45 PDT 2025
https://github.com/shashi1687 created https://github.com/llvm/llvm-project/pull/148555
`VPValue::getDefiningRecipe()` can return the ilist sentinel for live-in
values. Dereferencing that sentinel trips the “dyn_cast on a non-existent
value” assertion (PR #148389).
* Collapse sentinel → nullptr with a small helper.
* Replace plain `isa`/`dyn_cast` with `isa_and_present` / `dyn_cast_if_present`.
* Keep old behaviour for non-sentinel recipes, so the chosen VF doesn’t change.
Added lit test `Transforms/LoopVectorize/pr148389-sentinel.ll`.
Fixes: #148389
>From f8905edecb1a3a304136edbc055e057d6858524f Mon Sep 17 00:00:00 2001
From: Shashi Shankar <shashishankar1687 at gmail.com>
Date: Mon, 14 Jul 2025 01:16:51 +0200
Subject: [PATCH] [VPlan] Guard VPPartialReductionRecipe::computeCost against
ilist sentinel (#148389)
---
.../lib/Transforms/Vectorize/VPlanRecipes.cpp | 30 ++++++++++++-------
.../LoopVectorize/PR148389-sentinel.ll | 27 +++++++++++++++++
2 files changed, 46 insertions(+), 11 deletions(-)
create mode 100644 llvm/test/Transforms/LoopVectorize/PR148389-sentinel.ll
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index 3c367664a0988..fc918c669df12 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -296,24 +296,32 @@ bool VPRecipeBase::isScalarCast() const {
InstructionCost
VPPartialReductionRecipe::computeCost(ElementCount VF,
VPCostContext &Ctx) const {
+ // -----------------------------------------------------------------------
+ // Helpers that treat an ilist *sentinel* exactly like `nullptr`.
+ // -----------------------------------------------------------------------
+ auto safe = [](VPRecipeBase *R) -> VPRecipeBase * {
+ return isa_and_present<VPRecipeBase>(R) ? R : nullptr;
+ };
+
std::optional<unsigned> Opcode;
- VPValue *Op = getOperand(0);
- VPRecipeBase *OpR = Op->getDefiningRecipe();
+ VPValue *Op = getOperand(0);
+ VPRecipeBase *OpR = safe(Op->getDefiningRecipe());
// If the partial reduction is predicated, a select will be operand 0
using namespace llvm::VPlanPatternMatch;
if (match(getOperand(1), m_Select(m_VPValue(), m_VPValue(Op), m_VPValue()))) {
- OpR = Op->getDefiningRecipe();
+ OpR = safe(Op->getDefiningRecipe());
}
Type *InputTypeA = nullptr, *InputTypeB = nullptr;
TTI::PartialReductionExtendKind ExtAType = TTI::PR_None,
ExtBType = TTI::PR_None;
- auto GetExtendKind = [](VPRecipeBase *R) {
+ auto GetExtendKind = [&](VPRecipeBase *R) {
+ R = safe(R);
if (!R)
return TTI::PR_None;
- auto *WidenCastR = dyn_cast<VPWidenCastRecipe>(R);
+ auto *WidenCastR = dyn_cast_if_present<VPWidenCastRecipe>(R);
if (!WidenCastR)
return TTI::PR_None;
if (WidenCastR->getOpcode() == Instruction::CastOps::ZExt)
@@ -328,11 +336,11 @@ VPPartialReductionRecipe::computeCost(ElementCount VF,
auto HandleWiden = [&](VPWidenRecipe *Widen) {
if (match(Widen,
m_Binary<Instruction::Sub>(m_SpecificInt(0), m_VPValue(Op)))) {
- Widen = dyn_cast<VPWidenRecipe>(Op->getDefiningRecipe());
+ Widen = dyn_cast_if_present<VPWidenRecipe>(safe(Op->getDefiningRecipe()));
}
Opcode = Widen->getOpcode();
- VPRecipeBase *ExtAR = Widen->getOperand(0)->getDefiningRecipe();
- VPRecipeBase *ExtBR = Widen->getOperand(1)->getDefiningRecipe();
+ VPRecipeBase *ExtAR = safe(Widen->getOperand(0)->getDefiningRecipe());
+ VPRecipeBase *ExtBR = safe(Widen->getOperand(1)->getDefiningRecipe());
InputTypeA = Ctx.Types.inferScalarType(ExtAR ? ExtAR->getOperand(0)
: Widen->getOperand(0));
InputTypeB = Ctx.Types.inferScalarType(ExtBR ? ExtBR->getOperand(0)
@@ -341,7 +349,7 @@ VPPartialReductionRecipe::computeCost(ElementCount VF,
ExtBType = GetExtendKind(ExtBR);
};
- if (isa<VPWidenCastRecipe>(OpR)) {
+ if (isa_and_present<VPWidenCastRecipe>(OpR)) {
InputTypeA = Ctx.Types.inferScalarType(OpR->getOperand(0));
ExtAType = GetExtendKind(OpR);
} else if (isa<VPReductionPHIRecipe>(OpR)) {
@@ -351,9 +359,9 @@ VPPartialReductionRecipe::computeCost(ElementCount VF,
ExtAType = GetExtendKind(RedPhiOp1R);
} else if (auto Widen = dyn_cast<VPWidenRecipe>(RedPhiOp1R))
HandleWiden(Widen);
- } else if (auto Widen = dyn_cast<VPWidenRecipe>(OpR)) {
+ } else if (auto Widen = dyn_cast_if_present<VPWidenRecipe>(OpR)) {
HandleWiden(Widen);
- } else if (auto Reduction = dyn_cast<VPPartialReductionRecipe>(OpR)) {
+ } else if (auto Reduction = dyn_cast_if_present<VPReductionRecipe>(OpR)) {
return Reduction->computeCost(VF, Ctx);
}
auto *PhiType = Ctx.Types.inferScalarType(getOperand(1));
diff --git a/llvm/test/Transforms/LoopVectorize/PR148389-sentinel.ll b/llvm/test/Transforms/LoopVectorize/PR148389-sentinel.ll
new file mode 100644
index 0000000000000..d0c7392302275
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/PR148389-sentinel.ll
@@ -0,0 +1,27 @@
+; RUN: opt -passes=loop-vectorize -mcpu=grace -S %s -o /dev/null
+; REQUIRES: aarch64-registered-target
+
+; Reduced from GitHub issue #148389.
+; The test just needs to run – if the pass crashes the test will fail.
+
+define void @h(ptr %e, ptr %f, i8 %d) {
+entry:
+ br label %body
+body:
+ %i = phi i16 [0, %entry], [%inc, %latch]
+ %idx = sext i16 %i to i64
+ %eelt = getelementptr [1 x i16], ptr %e, i64 %idx, i64 %idx
+ %eval = load i16, ptr %eelt
+ %felt = getelementptr [7 x i8], ptr %f, i64 %idx, i64 %idx
+ %fval = load i8, ptr %felt
+ %cmp = icmp eq i8 %d, 0
+ br i1 %cmp, label %update, label %latch
+update:
+ br label %latch
+latch:
+ %inc = add nuw nsw i16 %i, 1
+ %exit = icmp eq i16 %inc, 17
+ br i1 %exit, label %exit.block, label %body
+exit.block:
+ ret void
+}
More information about the llvm-commits
mailing list