[llvm] [InstCombineCasts] Undef -> poison only for certain optimizations (PR #201631)
Sean Clarke via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 4 09:51:32 PDT 2026
https://github.com/xarkenz created https://github.com/llvm/llvm-project/pull/201631
Further deprecate UndefValue by restricting several related optimizations in InstCombineCasts to PoisonValue only.
>From 987ac74c80bed50ca510796082f1ad70663e3a09 Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Tue, 2 Jun 2026 17:20:08 -0500
Subject: [PATCH] Undef -> poison in InstCombineCasts
---
llvm/include/llvm/IR/PatternMatch.h | 15 ++++-
.../llvm/Support/PatternMatchHelpers.h | 8 +--
.../InstCombine/InstCombineCasts.cpp | 65 +++++++++----------
llvm/test/Transforms/InstCombine/fpextend.ll | 10 +--
.../InstCombine/vector-casts-inseltpoison.ll | 28 ++++----
.../Transforms/InstCombine/vector-casts.ll | 28 ++++----
6 files changed, 80 insertions(+), 74 deletions(-)
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 430f867875f43..215f939c79dad 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -1957,15 +1957,22 @@ template <typename T0, typename T1, typename T2> struct Shuffle_match {
}
};
-struct m_Mask {
+struct Mask_match {
ArrayRef<int> &MaskRef;
- m_Mask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
+ Mask_match(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
bool match(ArrayRef<int> Mask) const {
MaskRef = Mask;
return true;
}
};
+inline Mask_match m_Mask(ArrayRef<int> &MaskRef) { return Mask_match(MaskRef); }
+
+template <typename Pattern>
+inline auto m_Mask(ArrayRef<int> &MaskRef, const Pattern &P) {
+ return m_CombineAnd(P, m_Mask(MaskRef));
+}
+
struct m_ZeroMask {
bool match(ArrayRef<int> Mask) const {
return all_of(Mask, [](int Elem) { return Elem == 0 || Elem == -1; });
@@ -1978,6 +1985,10 @@ struct m_SpecificMask {
bool match(ArrayRef<int> Mask) const { return Val == Mask; }
};
+struct m_SplatMask {
+ bool match(ArrayRef<int> Mask) const { return all_equal(Mask); }
+};
+
struct m_SplatOrPoisonMask {
int &SplatIndex;
m_SplatOrPoisonMask(int &SplatIndex) : SplatIndex(SplatIndex) {}
diff --git a/llvm/include/llvm/Support/PatternMatchHelpers.h b/llvm/include/llvm/Support/PatternMatchHelpers.h
index 4549a14b740cd..3f23c2c268ca7 100644
--- a/llvm/include/llvm/Support/PatternMatchHelpers.h
+++ b/llvm/include/llvm/Support/PatternMatchHelpers.h
@@ -19,7 +19,7 @@
namespace llvm::PatternMatchHelpers {
/// Matching or combinator leaf case.
template <typename... Tys> struct match_combine_or { // NOLINT
- template <typename ITy> bool match(ITy *) const { return false; }
+ template <typename ITy> bool match(ITy) const { return false; }
};
/// Matching or combinator.
@@ -29,14 +29,14 @@ struct match_combine_or<Ty, Tys...> : match_combine_or<Tys...> {
match_combine_or(const Ty &P, const Tys &...Ps)
: match_combine_or<Tys...>(Ps...), P(P) {}
- template <typename ITy> bool match(ITy *V) const {
+ template <typename ITy> bool match(ITy V) const {
return P.match(V) || match_combine_or<Tys...>::match(V);
}
};
/// Matching and combinator leaf case.
template <typename... Tys> struct match_combine_and { // NOLINT
- template <typename ITy> bool match(ITy *) const { return true; }
+ template <typename ITy> bool match(ITy) const { return true; }
};
/// Matching and combinator.
@@ -46,7 +46,7 @@ struct match_combine_and<Ty, Tys...> : match_combine_and<Tys...> {
match_combine_and(const Ty &P, const Tys &...Ps)
: match_combine_and<Tys...>(Ps...), P(P) {}
- template <typename ITy> bool match(ITy *V) const {
+ template <typename ITy> bool match(ITy V) const {
return P.match(V) && match_combine_and<Tys...>::match(V);
}
};
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index d371218e61108..10185368f4d62 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -269,7 +269,7 @@ Instruction *InstCombinerImpl::commonCastTransforms(CastInst &CI) {
// cast (shuffle X, Mask) --> shuffle (cast X), Mask
Value *X;
ArrayRef<int> Mask;
- if (match(Src, m_OneUse(m_Shuffle(m_Value(X), m_Undef(), m_Mask(Mask))))) {
+ if (match(Src, m_OneUse(m_Shuffle(m_Value(X), m_Poison(), m_Mask(Mask))))) {
// TODO: Allow scalable vectors?
auto *SrcTy = dyn_cast<FixedVectorType>(X->getType());
auto *DestTy = dyn_cast<FixedVectorType>(Ty);
@@ -977,25 +977,26 @@ Instruction *InstCombinerImpl::narrowBinOp(TruncInst &Trunc) {
/// creating a shuffle type that targets may not be able to lower effectively.
static Instruction *shrinkSplatShuffle(TruncInst &Trunc,
InstCombiner::BuilderTy &Builder) {
- auto *Shuf = dyn_cast<ShuffleVectorInst>(Trunc.getOperand(0));
- if (Shuf && Shuf->hasOneUse() && match(Shuf->getOperand(1), m_Undef()) &&
- all_equal(Shuf->getShuffleMask()) &&
- ElementCount::isKnownGE(Shuf->getType()->getElementCount(),
- cast<VectorType>(Shuf->getOperand(0)->getType())
- ->getElementCount())) {
- // trunc (shuf X, Undef, SplatMask) --> shuf (trunc X), Poison, SplatMask
- // trunc (shuf X, Poison, SplatMask) --> shuf (trunc X), Poison, SplatMask
- Type *NewTruncTy = Shuf->getOperand(0)->getType()->getWithNewType(
- Trunc.getType()->getScalarType());
- Value *NarrowOp = Builder.CreateTrunc(Shuf->getOperand(0), NewTruncTy);
- return new ShuffleVectorInst(NarrowOp, Shuf->getShuffleMask());
+ Value *ShufVec;
+ ArrayRef<int> SplatMask;
+ if (match(Trunc.getOperand(0),
+ m_OneUse(m_Shuffle(m_Value(ShufVec), m_Poison(),
+ m_Mask(SplatMask, m_SplatMask())))) &&
+ ElementCount::isKnownGE(
+ cast<VectorType>(Trunc.getOperand(0)->getType())->getElementCount(),
+ cast<VectorType>(ShufVec->getType())->getElementCount())) {
+ // trunc (shuf X, poison, SplatMask) --> shuf (trunc X), poison, SplatMask
+ Value *NarrowOp = Builder.CreateTrunc(
+ ShufVec,
+ ShufVec->getType()->getWithNewType(Trunc.getType()->getScalarType()));
+ return new ShuffleVectorInst(NarrowOp, SplatMask);
}
return nullptr;
}
/// Try to narrow the width of an insert element. This could be generalized for
-/// any vector constant, but we limit the transform to insertion into undef to
+/// any vector constant, but we limit the transform to insertion into poison to
/// avoid potential backend problems from unsupported insertion widths. This
/// could also be extended to handle the case of inserting a scalar constant
/// into a vector variable.
@@ -1005,22 +1006,15 @@ static Instruction *shrinkInsertElt(CastInst &Trunc,
assert((Opcode == Instruction::Trunc || Opcode == Instruction::FPTrunc) &&
"Unexpected instruction for shrinking");
- auto *InsElt = dyn_cast<InsertElementInst>(Trunc.getOperand(0));
- if (!InsElt || !InsElt->hasOneUse())
- return nullptr;
-
- Type *DestTy = Trunc.getType();
- Type *DestScalarTy = DestTy->getScalarType();
- Value *VecOp = InsElt->getOperand(0);
- Value *ScalarOp = InsElt->getOperand(1);
- Value *Index = InsElt->getOperand(2);
-
- if (match(VecOp, m_Undef())) {
- // trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
- // fptrunc (inselt undef, X, Index) --> inselt undef, (fptrunc X), Index
- UndefValue *NarrowUndef = UndefValue::get(DestTy);
- Value *NarrowOp = Builder.CreateCast(Opcode, ScalarOp, DestScalarTy);
- return InsertElementInst::Create(NarrowUndef, NarrowOp, Index);
+ Value *Elt, *Index;
+ if (match(Trunc.getOperand(0),
+ m_OneUse(m_InsertElt(m_Poison(), m_Value(Elt), m_Value(Index))))) {
+ // trunc (inselt poison, X, Index) --> inselt poison, (trunc X), Index
+ // fptrunc (inselt poison, X, Index) --> inselt poison, (fptrunc X), Index
+ auto *NarrowPoison = PoisonValue::get(Trunc.getType());
+ Value *NarrowOp =
+ Builder.CreateCast(Opcode, Elt, Trunc.getType()->getScalarType());
+ return InsertElementInst::Create(NarrowPoison, NarrowOp, Index);
}
return nullptr;
@@ -2069,11 +2063,11 @@ static Type *shrinkFPConstantVector(Value *V, bool PreferBFloat) {
// For fixed-width vectors we find the minimal type by looking
// through the constant values of the vector.
- for (unsigned i = 0; i != NumElts; ++i) {
- if (isa<UndefValue>(CV->getAggregateElement(i)))
+ for (unsigned I = 0; I != NumElts; ++I) {
+ if (match(CV->getAggregateElement(I), m_Poison()))
continue;
- auto *CFP = dyn_cast_or_null<ConstantFP>(CV->getAggregateElement(i));
+ auto *CFP = dyn_cast_or_null<ConstantFP>(CV->getAggregateElement(I));
if (!CFP)
return nullptr;
@@ -2763,8 +2757,9 @@ static bool collectInsertionElements(Value *V, unsigned Shift,
assert(isMultipleOfTypeSize(Shift, VecEltTy) &&
"Shift should be a multiple of the element type size");
- // Undef values never contribute useful bits to the result.
- if (isa<UndefValue>(V)) return true;
+ // Poison values never contribute useful bits to the result.
+ if (match(V, m_Poison()))
+ return true;
// If we got down to a value of the right type, we win, try inserting into the
// right element.
diff --git a/llvm/test/Transforms/InstCombine/fpextend.ll b/llvm/test/Transforms/InstCombine/fpextend.ll
index 28599613fd159..32327f5daea3c 100644
--- a/llvm/test/Transforms/InstCombine/fpextend.ll
+++ b/llvm/test/Transforms/InstCombine/fpextend.ll
@@ -82,14 +82,14 @@ define <2 x float> @test6(<2 x float> %x) nounwind {
ret <2 x float> %t34
}
-; Test with an undef element
-define <2 x float> @test6_undef(<2 x float> %x) nounwind {
-; CHECK-LABEL: @test6_undef(
-; CHECK-NEXT: [[T34:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float undef>
+; Test with a poison element
+define <2 x float> @test6_poison(<2 x float> %x) nounwind {
+; CHECK-LABEL: @test6_poison(
+; CHECK-NEXT: [[T34:%.*]] = fadd <2 x float> [[X:%.*]], <float 0.000000e+00, float poison>
; CHECK-NEXT: ret <2 x float> [[T34]]
;
%t1 = fpext <2 x float> %x to <2 x double>
- %t3 = fadd <2 x double> %t1, <double 0.000000e+00, double undef>
+ %t3 = fadd <2 x double> %t1, <double 0.000000e+00, double poison>
%t34 = fptrunc <2 x double> %t3 to <2 x float>
ret <2 x float> %t34
}
diff --git a/llvm/test/Transforms/InstCombine/vector-casts-inseltpoison.ll b/llvm/test/Transforms/InstCombine/vector-casts-inseltpoison.ll
index 5770e2ce72020..3d47f99a9bc5e 100644
--- a/llvm/test/Transforms/InstCombine/vector-casts-inseltpoison.ll
+++ b/llvm/test/Transforms/InstCombine/vector-casts-inseltpoison.ll
@@ -288,30 +288,30 @@ define <8 x i32> @pr24458(<8 x float> %n) {
ret <8 x i32> %wrong
}
-; Hoist a trunc to a scalar if we're inserting into an undef vector.
-; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
+; Hoist a trunc to a scalar if we're inserting into a poison vector.
+; trunc (inselt poison, X, Index) --> inselt poison, (trunc X), Index
-define <3 x i16> @trunc_inselt_undef(i32 %x) {
-; CHECK-LABEL: @trunc_inselt_undef(
+define <3 x i16> @trunc_inselt_poison(i32 %x, i32 %index) {
+; CHECK-LABEL: @trunc_inselt_poison(
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
-; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <3 x i16> <i16 undef, i16 poison, i16 undef>, i16 [[TMP1]], i64 1
+; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <3 x i16> poison, i16 [[TMP1]], i32 [[INDEX:%.*]]
; CHECK-NEXT: ret <3 x i16> [[TRUNC]]
;
- %vec = insertelement <3 x i32> poison, i32 %x, i32 1
+ %vec = insertelement <3 x i32> poison, i32 %x, i32 %index
%trunc = trunc <3 x i32> %vec to <3 x i16>
ret <3 x i16> %trunc
}
-; Hoist a trunc to a scalar if we're inserting into an undef vector.
-; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
+; Hoist a trunc to a scalar if we're inserting into a poison vector.
+; trunc (inselt poison, X, Index) --> inselt poison, (trunc X), Index
-define <2 x float> @fptrunc_inselt_undef(double %x, i32 %index) {
-; CHECK-LABEL: @fptrunc_inselt_undef(
+define <2 x float> @fptrunc_inselt_poison(double %x, i32 %index) {
+; CHECK-LABEL: @fptrunc_inselt_poison(
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[X:%.*]] to float
-; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <2 x float> undef, float [[TMP1]], i32 [[INDEX:%.*]]
+; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <2 x float> poison, float [[TMP1]], i32 [[INDEX:%.*]]
; CHECK-NEXT: ret <2 x float> [[TRUNC]]
;
- %vec = insertelement <2 x double> <double undef, double undef>, double %x, i32 %index
+ %vec = insertelement <2 x double> poison, double %x, i32 %index
%trunc = fptrunc <2 x double> %vec to <2 x float>
ret <2 x float> %trunc
}
@@ -337,11 +337,11 @@ define <3 x i16> @trunc_inselt1(i32 %x) {
define <2 x float> @fptrunc_inselt1(double %x, i32 %index) {
; CHECK-LABEL: @fptrunc_inselt1(
-; CHECK-NEXT: [[VEC:%.*]] = insertelement <2 x double> <double undef, double 3.000000e+00>, double [[X:%.*]], i32 [[INDEX:%.*]]
+; CHECK-NEXT: [[VEC:%.*]] = insertelement <2 x double> <double poison, double 3.000000e+00>, double [[X:%.*]], i32 [[INDEX:%.*]]
; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc <2 x double> [[VEC]] to <2 x float>
; CHECK-NEXT: ret <2 x float> [[TRUNC]]
;
- %vec = insertelement <2 x double> <double undef, double 3.0>, double %x, i32 %index
+ %vec = insertelement <2 x double> <double poison, double 3.0>, double %x, i32 %index
%trunc = fptrunc <2 x double> %vec to <2 x float>
ret <2 x float> %trunc
}
diff --git a/llvm/test/Transforms/InstCombine/vector-casts.ll b/llvm/test/Transforms/InstCombine/vector-casts.ll
index 56e957d543078..2a2448a9e6ad9 100644
--- a/llvm/test/Transforms/InstCombine/vector-casts.ll
+++ b/llvm/test/Transforms/InstCombine/vector-casts.ll
@@ -288,30 +288,30 @@ define <8 x i32> @pr24458(<8 x float> %n) {
ret <8 x i32> %wrong
}
-; Hoist a trunc to a scalar if we're inserting into an undef vector.
-; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
+; Hoist a trunc to a scalar if we're inserting into a poison vector.
+; trunc (inselt poison, X, Index) --> inselt poison, (trunc X), Index
-define <3 x i16> @trunc_inselt_undef(i32 %x) {
-; CHECK-LABEL: @trunc_inselt_undef(
+define <3 x i16> @trunc_inselt_poison(i32 %x, i32 %index) {
+; CHECK-LABEL: @trunc_inselt_poison(
; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[X:%.*]] to i16
-; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <3 x i16> <i16 undef, i16 poison, i16 undef>, i16 [[TMP1]], i64 1
+; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <3 x i16> poison, i16 [[TMP1]], i32 [[INDEX:%.*]]
; CHECK-NEXT: ret <3 x i16> [[TRUNC]]
;
- %vec = insertelement <3 x i32> undef, i32 %x, i32 1
+ %vec = insertelement <3 x i32> poison, i32 %x, i32 %index
%trunc = trunc <3 x i32> %vec to <3 x i16>
ret <3 x i16> %trunc
}
-; Hoist a trunc to a scalar if we're inserting into an undef vector.
-; trunc (inselt undef, X, Index) --> inselt undef, (trunc X), Index
+; Hoist a trunc to a scalar if we're inserting into a poison vector.
+; trunc (inselt poison, X, Index) --> inselt poison, (trunc X), Index
-define <2 x float> @fptrunc_inselt_undef(double %x, i32 %index) {
-; CHECK-LABEL: @fptrunc_inselt_undef(
+define <2 x float> @fptrunc_inselt_poison(double %x, i32 %index) {
+; CHECK-LABEL: @fptrunc_inselt_poison(
; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[X:%.*]] to float
-; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <2 x float> undef, float [[TMP1]], i32 [[INDEX:%.*]]
+; CHECK-NEXT: [[TRUNC:%.*]] = insertelement <2 x float> poison, float [[TMP1]], i32 [[INDEX:%.*]]
; CHECK-NEXT: ret <2 x float> [[TRUNC]]
;
- %vec = insertelement <2 x double> <double undef, double undef>, double %x, i32 %index
+ %vec = insertelement <2 x double> poison, double %x, i32 %index
%trunc = fptrunc <2 x double> %vec to <2 x float>
ret <2 x float> %trunc
}
@@ -337,11 +337,11 @@ define <3 x i16> @trunc_inselt1(i32 %x) {
define <2 x float> @fptrunc_inselt1(double %x, i32 %index) {
; CHECK-LABEL: @fptrunc_inselt1(
-; CHECK-NEXT: [[VEC:%.*]] = insertelement <2 x double> <double undef, double 3.000000e+00>, double [[X:%.*]], i32 [[INDEX:%.*]]
+; CHECK-NEXT: [[VEC:%.*]] = insertelement <2 x double> <double poison, double 3.000000e+00>, double [[X:%.*]], i32 [[INDEX:%.*]]
; CHECK-NEXT: [[TRUNC:%.*]] = fptrunc <2 x double> [[VEC]] to <2 x float>
; CHECK-NEXT: ret <2 x float> [[TRUNC]]
;
- %vec = insertelement <2 x double> <double undef, double 3.0>, double %x, i32 %index
+ %vec = insertelement <2 x double> <double poison, double 3.0>, double %x, i32 %index
%trunc = fptrunc <2 x double> %vec to <2 x float>
ret <2 x float> %trunc
}
More information about the llvm-commits
mailing list