[llvm] [AArch64][SVE] Fold nested boolean UMIN trees (PR #209234)
Matthew Devereau via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 31 07:13:16 PDT 2026
https://github.com/MDevereau updated https://github.com/llvm/llvm-project/pull/209234
>From f0a6e03d5c9db0887f694c34feaf05ada44f39e0 Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Wed, 29 Jul 2026 15:31:58 +0000
Subject: [PATCH 1/6] [AArch64][SVE] Fold nested boolean UMIN trees
Fold redundant UMIN clamps in logical boolean reduction trees when all
operations use the same predicate.
---
.../AArch64/AArch64TargetTransformInfo.cpp | 35 ++++++
.../AArch64/sve-intrinsic-opts-cmpne.ll | 100 ++++++++++++++++++
2 files changed, 135 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 8642cb9a3ca08..4f5b0a24a6f3f 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -3366,6 +3366,39 @@ instCombineInStreamingMode(InstCombiner &IC, IntrinsicInst &II) {
return std::nullopt;
}
+static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
+ IntrinsicInst &II) {
+ Value *Pg = II.getOperand(0);
+ auto getUMinOpFromBooleanUMin = [&Pg](Value *UMin) -> IntrinsicInst * {
+ Value *LHS;
+ if (!match(UMin, m_Intrinsic<Intrinsic::aarch64_sve_umin_u>(
+ m_Specific(Pg), m_Value(LHS), m_One())))
+ return nullptr;
+ if (!match(LHS, m_Intrinsic<Intrinsic::aarch64_sve_umin_u>(
+ m_Specific(Pg), m_Value(), m_Value())))
+ return nullptr;
+
+ return cast<IntrinsicInst>(LHS);
+ };
+
+ IntrinsicInst *OuterUMin = getUMinOpFromBooleanUMin(&II);
+ if (!OuterUMin || !OuterUMin->hasOneUse())
+ return std::nullopt;
+
+ IntrinsicInst *LHS = getUMinOpFromBooleanUMin(OuterUMin->getOperand(1));
+ IntrinsicInst *RHS = getUMinOpFromBooleanUMin(OuterUMin->getOperand(2));
+ if (!LHS || !RHS)
+ return std::nullopt;
+
+ Value *NewUMin = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_umin_u,
+ II.getType(), {Pg, LHS, RHS});
+ Value *NewBooleanUMin =
+ IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_umin_u, II.getType(),
+ {Pg, NewUMin, II.getOperand(2)});
+
+ return IC.replaceInstUsesWith(II, NewBooleanUMin);
+}
+
std::optional<Instruction *>
AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
IntrinsicInst &II) const {
@@ -3485,6 +3518,8 @@ AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
return instCombineSVEUxt(IC, II, 32);
case Intrinsic::aarch64_sme_in_streaming_mode:
return instCombineInStreamingMode(IC, II);
+ case Intrinsic::aarch64_sve_umin_u:
+ return instCombineSVEUMin(IC, II);
}
return std::nullopt;
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
index d9a5434c35269..c490595eb3eab 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
@@ -572,6 +572,106 @@ define <vscale x 16 x i1> @dupq_b_idx(i64 %idx) #0 {
ret <vscale x 16 x i1> %5
}
+define <vscale x 16 x i8> @logical_bool_tree_i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP3]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+ %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+ %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
+ %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+ %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
+ %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+ %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
+ ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_i8_multiuse_outer_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_multiuse_outer_umin(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP2]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: call void (...) @llvm.fake.use(<vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+ %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+ %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
+ %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+ %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
+ %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+ %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
+ call void (...) @llvm.fake.use(<vscale x 16 x i8> %abcd)
+ ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_outer_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_outer_umin(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[ABCD]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+ %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+ %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
+ %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+ %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
+ %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+ %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
+ ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_inner_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_inner_umin(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[ABCD]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+ %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+ %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
+ %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+ %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
+ %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+ %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
+ ret <vscale x 16 x i8> %abcd.bool
+}
+
+define <vscale x 16 x i8> @logical_bool_tree_i8_nonboolean_clamp(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_nonboolean_clamp(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
+; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
+; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[ABCD]], <vscale x 16 x i8> splat (i8 2))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
+;
+ %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
+ %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
+ %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
+ %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
+ %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
+ %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 2))
+ ret <vscale x 16 x i8> %abcd.bool
+}
+
declare <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32)
declare <vscale x 16 x i8> @llvm.vector.insert.nxv16i8.v16i8(<vscale x 16 x i8>, <16 x i8>, i64)
>From 601d6c39df3a497786b9025e201f283a26253f3c Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Wed, 29 Jul 2026 16:35:36 +0000
Subject: [PATCH 2/6] add comment
---
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 4f5b0a24a6f3f..e356f1f6c49bf 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -3368,6 +3368,15 @@ instCombineInStreamingMode(InstCombiner &IC, IntrinsicInst &II) {
static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
IntrinsicInst &II) {
+ // Fold umin(umin(umin(umin(A, B), 1),
+ // umin(umin(C, D), 1)),
+ // 1)
+ // into
+ // umin(umin(umin(A, B),
+ // umin(C, D)),
+ // 1),
+ // removing two redundant boolean umins when predication is equal across all
+ // umins.
Value *Pg = II.getOperand(0);
auto getUMinOpFromBooleanUMin = [&Pg](Value *UMin) -> IntrinsicInst * {
Value *LHS;
>From c14b388cdf39028ec294856fa458d5f0c7c5829c Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Thu, 30 Jul 2026 16:50:25 +0000
Subject: [PATCH 3/6] Rework patch to two simpler combines
---
.../AArch64/AArch64TargetTransformInfo.cpp | 59 ++++----
.../AArch64/sve-intrinsic-opts-cmpne.ll | 100 --------------
.../AArch64/sve-intrinsic-opts-umin.ll | 126 ++++++++++++++++++
3 files changed, 149 insertions(+), 136 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index e356f1f6c49bf..e23371c8873e5 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -3368,44 +3368,31 @@ instCombineInStreamingMode(InstCombiner &IC, IntrinsicInst &II) {
static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
IntrinsicInst &II) {
- // Fold umin(umin(umin(umin(A, B), 1),
- // umin(umin(C, D), 1)),
- // 1)
- // into
- // umin(umin(umin(A, B),
- // umin(C, D)),
- // 1),
- // removing two redundant boolean umins when predication is equal across all
- // umins.
+ // umin(umin(A, 1), umin(B, 1)) -> umin(umin(A,B), 1)
+ constexpr Intrinsic::ID UMinID = Intrinsic::aarch64_sve_umin_u;
+ Value *A, *B;
Value *Pg = II.getOperand(0);
- auto getUMinOpFromBooleanUMin = [&Pg](Value *UMin) -> IntrinsicInst * {
- Value *LHS;
- if (!match(UMin, m_Intrinsic<Intrinsic::aarch64_sve_umin_u>(
- m_Specific(Pg), m_Value(LHS), m_One())))
- return nullptr;
- if (!match(LHS, m_Intrinsic<Intrinsic::aarch64_sve_umin_u>(
- m_Specific(Pg), m_Value(), m_Value())))
- return nullptr;
+ if (match(II.getOperand(1),
+ m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(A), m_One())) &&
+ match(II.getOperand(2),
+ m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(B), m_One())) &&
+ II.hasOneUse()) {
+ Value *NewUMin =
+ IC.Builder.CreateIntrinsic(UMinID, II.getType(), {Pg, A, B});
+ Value *NewLogicalUMin = IC.Builder.CreateIntrinsic(
+ UMinID, II.getType(), {Pg, NewUMin, ConstantInt::get(II.getType(), 1)});
+ return IC.replaceInstUsesWith(II, NewLogicalUMin);
+ }
+
+ // umin(umin(A, 1), 1) -> umin(A, 1)
+ Value *InnerUMin;
+ if (match(&II,
+ m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(InnerUMin), m_One())) &&
+ match(InnerUMin,
+ m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(A), m_One())))
+ return IC.replaceInstUsesWith(II, InnerUMin);
- return cast<IntrinsicInst>(LHS);
- };
-
- IntrinsicInst *OuterUMin = getUMinOpFromBooleanUMin(&II);
- if (!OuterUMin || !OuterUMin->hasOneUse())
- return std::nullopt;
-
- IntrinsicInst *LHS = getUMinOpFromBooleanUMin(OuterUMin->getOperand(1));
- IntrinsicInst *RHS = getUMinOpFromBooleanUMin(OuterUMin->getOperand(2));
- if (!LHS || !RHS)
- return std::nullopt;
-
- Value *NewUMin = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_umin_u,
- II.getType(), {Pg, LHS, RHS});
- Value *NewBooleanUMin =
- IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_umin_u, II.getType(),
- {Pg, NewUMin, II.getOperand(2)});
-
- return IC.replaceInstUsesWith(II, NewBooleanUMin);
+ return std::nullopt;
}
std::optional<Instruction *>
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
index c490595eb3eab..d9a5434c35269 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
@@ -572,106 +572,6 @@ define <vscale x 16 x i1> @dupq_b_idx(i64 %idx) #0 {
ret <vscale x 16 x i1> %5
}
-define <vscale x 16 x i8> @logical_bool_tree_i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
-; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
-; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
-; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP3]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
-;
- %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
- %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
- %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
- %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
- %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
- %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
- ret <vscale x 16 x i8> %abcd.bool
-}
-
-define <vscale x 16 x i8> @logical_bool_tree_i8_multiuse_outer_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
-; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_multiuse_outer_umin(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
-; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
-; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
-; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP2]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: call void (...) @llvm.fake.use(<vscale x 16 x i8> [[TMP2]])
-; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
-;
- %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
- %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
- %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
- %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
- %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
- %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
- call void (...) @llvm.fake.use(<vscale x 16 x i8> %abcd)
- ret <vscale x 16 x i8> %abcd.bool
-}
-
-define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_outer_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
-; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_outer_umin(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
-; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
-; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
-; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[ABCD]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
-;
- %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
- %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
- %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
- %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
- %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
- %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
- ret <vscale x 16 x i8> %abcd.bool
-}
-
-define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_inner_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
-; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_inactive_inner_umin(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
-; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
-; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
-; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[ABCD]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
-;
- %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
- %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
- %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
- %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
- %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
- %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 1))
- ret <vscale x 16 x i8> %abcd.bool
-}
-
-define <vscale x 16 x i8> @logical_bool_tree_i8_nonboolean_clamp(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d) #0 {
-; CHECK-LABEL: define <vscale x 16 x i8> @logical_bool_tree_i8_nonboolean_clamp(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]], <vscale x 16 x i8> [[C:%.*]], <vscale x 16 x i8> [[D:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[AB:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
-; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[CD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[C]], <vscale x 16 x i8> [[D]])
-; CHECK-NEXT: [[CD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[CD]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[ABCD:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[AB_BOOL]], <vscale x 16 x i8> [[CD_BOOL]])
-; CHECK-NEXT: [[ABCD_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[ABCD]], <vscale x 16 x i8> splat (i8 2))
-; CHECK-NEXT: ret <vscale x 16 x i8> [[ABCD_BOOL]]
-;
- %ab = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b)
- %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab, <vscale x 16 x i8> splat (i8 1))
- %cd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %c, <vscale x 16 x i8> %d)
- %cd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %cd, <vscale x 16 x i8> splat (i8 1))
- %abcd = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %ab.bool, <vscale x 16 x i8> %cd.bool)
- %abcd.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %abcd, <vscale x 16 x i8> splat (i8 2))
- ret <vscale x 16 x i8> %abcd.bool
-}
-
declare <vscale x 2 x i1> @llvm.aarch64.sve.ptrue.nxv2i1(i32)
declare <vscale x 16 x i8> @llvm.vector.insert.nxv16i8.v16i8(<vscale x 16 x i8>, <16 x i8>, i64)
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
new file mode 100644
index 0000000000000..4b71eef26f30d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
@@ -0,0 +1,126 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; umin(umin(A, 1), umin(B, 1)) -> umin(umin(A,B), 1)
+
+define <vscale x 16 x i8> @umin_with_logical_umin_operands(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> [[B]])
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP2]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
+ ret <vscale x 16 x i8> %3
+}
+
+define <vscale x 16 x i8> @umin_with_operand_1_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_operand_1_umin(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 2))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 2))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
+ ret <vscale x 16 x i8> %3
+}
+
+define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_1(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_1(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
+ ret <vscale x 16 x i8> %3
+}
+
+define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_2(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_2(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
+ ret <vscale x 16 x i8> %3
+}
+
+define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_3(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_3(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
+ ret <vscale x 16 x i8> %3
+}
+
+; umin(umin(A, 1), 1) -> umin(A, 1)
+
+define <vscale x 16 x i8> @logical_umin_with_logical_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_umin_with_logical_umin(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP1]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> splat (i8 1))
+ ret <vscale x 16 x i8> %2
+}
+
+define <vscale x 16 x i8> @logical_umin_with_logical_umin_predicate_mismatch(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_umin_with_logical_umin_predicate_mismatch(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP2]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> splat (i8 1))
+ ret <vscale x 16 x i8> %2
+}
+
+define <vscale x 16 x i8> @logical_umin_with_umin_1(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_umin_with_umin_1(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 40))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP2]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 40))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> splat (i8 1))
+ ret <vscale x 16 x i8> %2
+}
+
+define <vscale x 16 x i8> @logical_umin_with_umin_2(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @logical_umin_with_umin_2(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> splat (i8 40))
+; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP2]]
+;
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> splat (i8 40))
+ ret <vscale x 16 x i8> %2
+}
+
+attributes #0 = { "target-features"="+sve" }
>From d691e4e8959b861ae37ff804c4c172fc04531698 Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Fri, 31 Jul 2026 12:29:37 +0000
Subject: [PATCH 4/6] Fix oneuse location
---
.../AArch64/AArch64TargetTransformInfo.cpp | 9 ++++-----
.../AArch64/sve-intrinsic-opts-umin.ll | 18 ++++++++++++++++++
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index e23371c8873e5..b6509ced5a74e 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -3372,11 +3372,10 @@ static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
constexpr Intrinsic::ID UMinID = Intrinsic::aarch64_sve_umin_u;
Value *A, *B;
Value *Pg = II.getOperand(0);
- if (match(II.getOperand(1),
- m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(A), m_One())) &&
- match(II.getOperand(2),
- m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(B), m_One())) &&
- II.hasOneUse()) {
+ if (match(II.getOperand(1), m_OneUse(m_Intrinsic<UMinID>(
+ m_Specific(Pg), m_Value(A), m_One()))) &&
+ match(II.getOperand(2), m_OneUse(m_Intrinsic<UMinID>(
+ m_Specific(Pg), m_Value(B), m_One())))) {
Value *NewUMin =
IC.Builder.CreateIntrinsic(UMinID, II.getType(), {Pg, A, B});
Value *NewLogicalUMin = IC.Builder.CreateIntrinsic(
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
index 4b71eef26f30d..cf75e94ba2d36 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
@@ -74,6 +74,24 @@ define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_3(
ret <vscale x 16 x i8> %3
}
+define <vscale x 16 x i8> @umin_with_multiuse_logical_umin_operands(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_multiuse_logical_umin_operands(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[A_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[B_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[AB_BOOL:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A_BOOL]], <vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT: call void (...) @llvm.fake.use(<vscale x 16 x i8> [[A_BOOL]])
+; CHECK-NEXT: call void (...) @llvm.fake.use(<vscale x 16 x i8> [[B_BOOL]])
+; CHECK-NEXT: ret <vscale x 16 x i8> [[AB_BOOL]]
+;
+ %a.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %b.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %ab.bool = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a.bool, <vscale x 16 x i8> %b.bool)
+ call void (...) @llvm.fake.use(<vscale x 16 x i8> %a.bool)
+ call void (...) @llvm.fake.use(<vscale x 16 x i8> %b.bool)
+ ret <vscale x 16 x i8> %ab.bool
+}
+
; umin(umin(A, 1), 1) -> umin(A, 1)
define <vscale x 16 x i8> @logical_umin_with_logical_umin(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
>From 2527f9aff46b5f84e1c8fdbfa647ad771ecc1e4c Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Fri, 31 Jul 2026 12:43:50 +0000
Subject: [PATCH 5/6] Include predicate changes
---
.../AArch64/sve-intrinsic-opts-umin.ll | 32 +++++++++----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
index cf75e94ba2d36..9b12b9a763778 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-umin.ll
@@ -32,44 +32,44 @@ define <vscale x 16 x i8> @umin_with_operand_1_umin(<vscale x 16 x i1> %pg, <vsc
ret <vscale x 16 x i8> %3
}
-define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_1(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_1(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_1(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[OTHER_PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
+; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[OTHER_PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
;
%1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
%2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
- %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
+ %3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
ret <vscale x 16 x i8> %3
}
-define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_2(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_2(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_2(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[OTHER_PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[OTHER_PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
;
- %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
%2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
%3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
ret <vscale x 16 x i8> %3
}
-define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_3(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
+define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_3(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> %b) #0 {
; CHECK-LABEL: define <vscale x 16 x i8> @umin_with_logical_umin_operands_predicate_mismatch_3(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[OTHER_PG:%.*]], <vscale x 16 x i8> [[A:%.*]], <vscale x 16 x i8> [[B:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[OTHER_PG]], <vscale x 16 x i8> [[B]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: [[TMP3:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> [[TMP2]])
; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP3]]
;
%1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
- %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
+ %2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %b, <vscale x 16 x i8> splat (i8 1))
%3 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> %2)
ret <vscale x 16 x i8> %3
}
@@ -105,14 +105,14 @@ define <vscale x 16 x i8> @logical_umin_with_logical_umin(<vscale x 16 x i1> %pg
ret <vscale x 16 x i8> %2
}
-define <vscale x 16 x i8> @logical_umin_with_logical_umin_predicate_mismatch(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+define <vscale x 16 x i8> @logical_umin_with_logical_umin_predicate_mismatch(<vscale x 16 x i1> %pg, <vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %a) #0 {
; CHECK-LABEL: define <vscale x 16 x i8> @logical_umin_with_logical_umin_predicate_mismatch(
-; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i1> [[OTHER_PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[OTHER_PG]], <vscale x 16 x i8> [[A]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[TMP1]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: ret <vscale x 16 x i8> [[TMP2]]
;
- %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
+ %1 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %other_pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 1))
%2 = call <vscale x 16 x i8> @llvm.aarch64.sve.umin.u.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %1, <vscale x 16 x i8> splat (i8 1))
ret <vscale x 16 x i8> %2
}
>From db66d1a345857903deeeb38ea3a2152b7411a81e Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Fri, 31 Jul 2026 14:06:03 +0000
Subject: [PATCH 6/6] Remove unused variables A and InnerUMin
---
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index b6509ced5a74e..7b1c603d4134c 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -3384,12 +3384,10 @@ static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
}
// umin(umin(A, 1), 1) -> umin(A, 1)
- Value *InnerUMin;
- if (match(&II,
- m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(InnerUMin), m_One())) &&
- match(InnerUMin,
- m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(A), m_One())))
- return IC.replaceInstUsesWith(II, InnerUMin);
+ if (match(II.getOperand(1),
+ m_Intrinsic<UMinID>(m_Specific(Pg), m_Value(), m_One())) &&
+ match(II.getOperand(2), m_One()))
+ return IC.replaceInstUsesWith(II, II.getOperand(1));
return std::nullopt;
}
More information about the llvm-commits
mailing list