[llvm] [LLVM][InstCombine] Enable simplification of SVE predicate binops. (PR #211016)
Paul Walker via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 23 05:35:45 PDT 2026
https://github.com/paulwalker-arm updated https://github.com/llvm/llvm-project/pull/211016
>From 2a56f747e0468ae9c9b33ef56639b308758673be Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Thu, 23 Jul 2026 12:08:59 +0000
Subject: [PATCH 1/5] Add tests to verify poison handling.
---
.../AArch64/sve-intrinsic-to-svbool-binops.ll | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
index abe1ed0fa37b8..2268c324e1fb8 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
@@ -40,6 +40,32 @@ define <vscale x 4 x i1> @try_combine_svbool_binop_and_2(<vscale x 4 x i1> %a, <
ret <vscale x 4 x i1> %t3
}
+define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_lhs(<vscale x 16 x i1> %a) {
+; CHECK-LABEL: @try_combine_svbool_logical_and_poison_lhs(
+; CHECK-NEXT: [[T1:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
+; CHECK-NEXT: [[T2:%.*]] = select <vscale x 16 x i1> [[T1]], <vscale x 16 x i1> [[A:%.*]], <vscale x 16 x i1> zeroinitializer
+; CHECK-NEXT: [[T3:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[T2]])
+; CHECK-NEXT: ret <vscale x 8 x i1> [[T3]]
+;
+ %t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
+ %t2 = select <vscale x 16 x i1> %t1, <vscale x 16 x i1> %a, <vscale x 16 x i1> zeroinitializer
+ %t3 = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> %t2)
+ ret <vscale x 8 x i1> %t3
+}
+
+define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_rhs(<vscale x 16 x i1> %a) {
+; CHECK-LABEL: @try_combine_svbool_logical_and_poison_rhs(
+; CHECK-NEXT: [[T1:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
+; CHECK-NEXT: [[T2:%.*]] = select <vscale x 16 x i1> [[A:%.*]], <vscale x 16 x i1> [[T1]], <vscale x 16 x i1> zeroinitializer
+; CHECK-NEXT: [[T3:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[T2]])
+; CHECK-NEXT: ret <vscale x 8 x i1> [[T3]]
+;
+ %t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
+ %t2 = select <vscale x 16 x i1> %a, <vscale x 16 x i1> %t1, <vscale x 16 x i1> zeroinitializer
+ %t3 = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> %t2)
+ ret <vscale x 8 x i1> %t3
+}
+
define <vscale x 2 x i1> @try_combine_svbool_binop_and_3(<vscale x 2 x i1> %a, <vscale x 16 x i1> %b) {
; CHECK-LABEL: @try_combine_svbool_binop_and_3(
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 2 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv2i1(<vscale x 16 x i1> [[B:%.*]])
>From 868d909c3f34fe90ff9ddeeecb1422833332250f Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Tue, 21 Jul 2026 14:27:29 +0100
Subject: [PATCH 2/5] [LLVM][InstCombine] Enable simplification of SVE
predicate binops.
Enable existing SVE binop simplification code paths for predicate
vectors. I've extended tryCombineFromSVBoolBinOp to maintain an
existing tranformation for the case where AND operations are replaced
by their SELECT equivalent.
---
.../AArch64/AArch64TargetTransformInfo.cpp | 65 ++++++++++++-------
.../AArch64/sve-intrinsic-to-svbool-binops.ll | 22 ++-----
2 files changed, 50 insertions(+), 37 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 960d50fb039f7..26a9f11710546 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -1727,7 +1727,6 @@ static SVEIntrinsicInfo constructSVEIntrinsicInfo(IntrinsicInst &II) {
Instruction::UDiv);
case Intrinsic::aarch64_sve_addqv:
- case Intrinsic::aarch64_sve_and_z:
case Intrinsic::aarch64_sve_bic_z:
case Intrinsic::aarch64_sve_brka_z:
case Intrinsic::aarch64_sve_brkb_z:
@@ -1736,13 +1735,11 @@ static SVEIntrinsicInfo constructSVEIntrinsicInfo(IntrinsicInst &II) {
case Intrinsic::aarch64_sve_brkpb_z:
case Intrinsic::aarch64_sve_cntp:
case Intrinsic::aarch64_sve_compact:
- case Intrinsic::aarch64_sve_eor_z:
case Intrinsic::aarch64_sve_eorv:
case Intrinsic::aarch64_sve_eorqv:
case Intrinsic::aarch64_sve_nand_z:
case Intrinsic::aarch64_sve_nor_z:
case Intrinsic::aarch64_sve_orn_z:
- case Intrinsic::aarch64_sve_orr_z:
case Intrinsic::aarch64_sve_orv:
case Intrinsic::aarch64_sve_orqv:
case Intrinsic::aarch64_sve_pnext:
@@ -1811,6 +1808,16 @@ static SVEIntrinsicInfo constructSVEIntrinsicInfo(IntrinsicInst &II) {
case Intrinsic::aarch64_sve_ldnt1_gather_uxtw:
return SVEIntrinsicInfo::defaultZeroingOp();
+ case Intrinsic::aarch64_sve_and_z:
+ return SVEIntrinsicInfo::defaultZeroingOp().setMatchingIROpcode(
+ Instruction::And);
+ case Intrinsic::aarch64_sve_orr_z:
+ return SVEIntrinsicInfo::defaultZeroingOp().setMatchingIROpcode(
+ Instruction::Or);
+ case Intrinsic::aarch64_sve_eor_z:
+ return SVEIntrinsicInfo::defaultZeroingOp().setMatchingIROpcode(
+ Instruction::Xor);
+
case Intrinsic::aarch64_sve_prf:
case Intrinsic::aarch64_sve_prfb_gather_index:
case Intrinsic::aarch64_sve_prfb_gather_scalar_offset:
@@ -1936,7 +1943,10 @@ simplifySVEIntrinsicBinOp(InstCombiner &IC, IntrinsicInst &II,
if (IInfo.inactiveLanesAreNotDefined())
return IC.replaceInstUsesWith(II, SimpleII);
- Value *Inactive = II.getOperand(IInfo.getOperandIdxInactiveLanesTakenFrom());
+ Value *Inactive =
+ IInfo.resultIsZeroInitialized()
+ ? Constant::getNullValue(II.getType())
+ : II.getOperand(IInfo.getOperandIdxInactiveLanesTakenFrom());
// The intrinsic does nothing (e.g. sve.mul(pg, A, 1.0)).
if (SimpleII == Inactive)
@@ -2006,11 +2016,30 @@ simplifySVEIntrinsic(InstCombiner &IC, IntrinsicInst &II,
// from_svbool is free.
static std::optional<Instruction *>
tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
+ auto m_ConvertToSVBool = [](auto P) {
+ return m_Intrinsic<Intrinsic::aarch64_sve_convert_to_svbool>(P);
+ };
+ auto CreateConvertFromSVBool = [&IC](Type *Ty, Value *V) {
+ unsigned IID = Intrinsic::aarch64_sve_convert_from_svbool;
+ return IC.Builder.CreateIntrinsic(IID, Ty, V);
+ };
+
+ Type *Ty = II.getType();
+ Value *NarrowLHS, *RHS;
+
+ if (match(II.getOperand(0),
+ m_c_LogicalAnd(m_ConvertToSVBool(m_SpecificType(Ty, NarrowLHS)),
+ m_Value(RHS)))) {
+ Value *NarrowRHS = CreateConvertFromSVBool(Ty, RHS);
+ Value *NarrowAnd = IC.Builder.CreateLogicalAnd(NarrowLHS, NarrowRHS);
+ return IC.replaceInstUsesWith(II, NarrowAnd);
+ }
+
auto BinOp = dyn_cast<IntrinsicInst>(II.getOperand(0));
if (!BinOp)
return std::nullopt;
- auto IntrinsicID = BinOp->getIntrinsicID();
+ Intrinsic::ID IntrinsicID = BinOp->getIntrinsicID();
switch (IntrinsicID) {
case Intrinsic::aarch64_sve_and_z:
case Intrinsic::aarch64_sve_bic_z:
@@ -2024,32 +2053,24 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
return std::nullopt;
}
- auto BinOpPred = BinOp->getOperand(0);
- auto BinOpOp1 = BinOp->getOperand(1);
- auto BinOpOp2 = BinOp->getOperand(2);
-
- auto PredIntr = dyn_cast<IntrinsicInst>(BinOpPred);
- if (!PredIntr ||
- PredIntr->getIntrinsicID() != Intrinsic::aarch64_sve_convert_to_svbool)
- return std::nullopt;
+ Value *BinOpPred = BinOp->getOperand(0);
+ Value *BinOpOp1 = BinOp->getOperand(1);
+ Value *BinOpOp2 = BinOp->getOperand(2);
- auto PredOp = PredIntr->getOperand(0);
- auto PredOpTy = cast<VectorType>(PredOp->getType());
- if (PredOpTy != II.getType())
+ Value *PredOp;
+ if (!match(BinOpPred, m_ConvertToSVBool(m_SpecificType(Ty, PredOp))))
return std::nullopt;
SmallVector<Value *> NarrowedBinOpArgs = {PredOp};
- auto NarrowBinOpOp1 = IC.Builder.CreateIntrinsic(
- Intrinsic::aarch64_sve_convert_from_svbool, {PredOpTy}, {BinOpOp1});
+ Value *NarrowBinOpOp1 = CreateConvertFromSVBool(Ty, BinOpOp1);
NarrowedBinOpArgs.push_back(NarrowBinOpOp1);
if (BinOpOp1 == BinOpOp2)
NarrowedBinOpArgs.push_back(NarrowBinOpOp1);
else
- NarrowedBinOpArgs.push_back(IC.Builder.CreateIntrinsic(
- Intrinsic::aarch64_sve_convert_from_svbool, {PredOpTy}, {BinOpOp2}));
+ NarrowedBinOpArgs.push_back(CreateConvertFromSVBool(Ty, BinOpOp2));
- auto NarrowedBinOp =
- IC.Builder.CreateIntrinsic(IntrinsicID, {PredOpTy}, NarrowedBinOpArgs);
+ Value *NarrowedBinOp =
+ IC.Builder.CreateIntrinsic(IntrinsicID, Ty, NarrowedBinOpArgs);
return IC.replaceInstUsesWith(II, NarrowedBinOp);
}
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
index 2268c324e1fb8..b0e57f434ceb1 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
@@ -19,7 +19,7 @@ define <vscale x 4 x i1> @try_combine_svbool_binop_and_0(<vscale x 4 x i1> %a, <
define <vscale x 8 x i1> @try_combine_svbool_binop_and_1(<vscale x 8 x i1> %a, <vscale x 16 x i1> %b) {
; CHECK-LABEL: @try_combine_svbool_binop_and_1(
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[B:%.*]])
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 8 x i1> @llvm.aarch64.sve.and.z.nxv8i1(<vscale x 8 x i1> [[A:%.*]], <vscale x 8 x i1> [[TMP1]], <vscale x 8 x i1> [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = select <vscale x 8 x i1> [[A:%.*]], <vscale x 8 x i1> [[TMP1]], <vscale x 8 x i1> zeroinitializer
; CHECK-NEXT: ret <vscale x 8 x i1> [[TMP2]]
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %a)
@@ -31,7 +31,7 @@ define <vscale x 8 x i1> @try_combine_svbool_binop_and_1(<vscale x 8 x i1> %a, <
define <vscale x 4 x i1> @try_combine_svbool_binop_and_2(<vscale x 4 x i1> %a, <vscale x 16 x i1> %b) {
; CHECK-LABEL: @try_combine_svbool_binop_and_2(
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv4i1(<vscale x 16 x i1> [[B:%.*]])
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.and.z.nxv4i1(<vscale x 4 x i1> [[A:%.*]], <vscale x 4 x i1> [[TMP1]], <vscale x 4 x i1> [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = select <vscale x 4 x i1> [[A:%.*]], <vscale x 4 x i1> [[TMP1]], <vscale x 4 x i1> zeroinitializer
; CHECK-NEXT: ret <vscale x 4 x i1> [[TMP2]]
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv4i1(<vscale x 4 x i1> %a)
@@ -42,10 +42,7 @@ define <vscale x 4 x i1> @try_combine_svbool_binop_and_2(<vscale x 4 x i1> %a, <
define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_lhs(<vscale x 16 x i1> %a) {
; CHECK-LABEL: @try_combine_svbool_logical_and_poison_lhs(
-; CHECK-NEXT: [[T1:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
-; CHECK-NEXT: [[T2:%.*]] = select <vscale x 16 x i1> [[T1]], <vscale x 16 x i1> [[A:%.*]], <vscale x 16 x i1> zeroinitializer
-; CHECK-NEXT: [[T3:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[T2]])
-; CHECK-NEXT: ret <vscale x 8 x i1> [[T3]]
+; CHECK-NEXT: ret <vscale x 8 x i1> poison
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
%t2 = select <vscale x 16 x i1> %t1, <vscale x 16 x i1> %a, <vscale x 16 x i1> zeroinitializer
@@ -55,10 +52,7 @@ define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_lhs(<vscale x 16
define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_rhs(<vscale x 16 x i1> %a) {
; CHECK-LABEL: @try_combine_svbool_logical_and_poison_rhs(
-; CHECK-NEXT: [[T1:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
-; CHECK-NEXT: [[T2:%.*]] = select <vscale x 16 x i1> [[A:%.*]], <vscale x 16 x i1> [[T1]], <vscale x 16 x i1> zeroinitializer
-; CHECK-NEXT: [[T3:%.*]] = tail call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[T2]])
-; CHECK-NEXT: ret <vscale x 8 x i1> [[T3]]
+; CHECK-NEXT: ret <vscale x 8 x i1> poison
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
%t2 = select <vscale x 16 x i1> %a, <vscale x 16 x i1> %t1, <vscale x 16 x i1> zeroinitializer
@@ -69,7 +63,7 @@ define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_rhs(<vscale x 16
define <vscale x 2 x i1> @try_combine_svbool_binop_and_3(<vscale x 2 x i1> %a, <vscale x 16 x i1> %b) {
; CHECK-LABEL: @try_combine_svbool_binop_and_3(
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 2 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv2i1(<vscale x 16 x i1> [[B:%.*]])
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 2 x i1> @llvm.aarch64.sve.and.z.nxv2i1(<vscale x 2 x i1> [[A:%.*]], <vscale x 2 x i1> [[TMP1]], <vscale x 2 x i1> [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = select <vscale x 2 x i1> [[A:%.*]], <vscale x 2 x i1> [[TMP1]], <vscale x 2 x i1> zeroinitializer
; CHECK-NEXT: ret <vscale x 2 x i1> [[TMP2]]
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv2i1(<vscale x 2 x i1> %a)
@@ -92,9 +86,7 @@ define <vscale x 8 x i1> @try_combine_svbool_binop_bic(<vscale x 8 x i1> %a, <vs
define <vscale x 8 x i1> @try_combine_svbool_binop_eor(<vscale x 8 x i1> %a, <vscale x 16 x i1> %b) {
; CHECK-LABEL: @try_combine_svbool_binop_eor(
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[B:%.*]])
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 8 x i1> @llvm.aarch64.sve.eor.z.nxv8i1(<vscale x 8 x i1> [[A:%.*]], <vscale x 8 x i1> [[TMP1]], <vscale x 8 x i1> [[TMP1]])
-; CHECK-NEXT: ret <vscale x 8 x i1> [[TMP2]]
+; CHECK-NEXT: ret <vscale x 8 x i1> zeroinitializer
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %a)
%t2 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.eor.z.nxv16i1(<vscale x 16 x i1> %t1, <vscale x 16 x i1> %b, <vscale x 16 x i1> %b)
@@ -141,7 +133,7 @@ define <vscale x 8 x i1> @try_combine_svbool_binop_orn(<vscale x 8 x i1> %a, <vs
define <vscale x 8 x i1> @try_combine_svbool_binop_orr(<vscale x 8 x i1> %a, <vscale x 16 x i1> %b) {
; CHECK-LABEL: @try_combine_svbool_binop_orr(
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 8 x i1> @llvm.aarch64.sve.convert.from.svbool.nxv8i1(<vscale x 16 x i1> [[B:%.*]])
-; CHECK-NEXT: [[TMP2:%.*]] = call <vscale x 8 x i1> @llvm.aarch64.sve.orr.z.nxv8i1(<vscale x 8 x i1> [[A:%.*]], <vscale x 8 x i1> [[TMP1]], <vscale x 8 x i1> [[TMP1]])
+; CHECK-NEXT: [[TMP2:%.*]] = select <vscale x 8 x i1> [[A:%.*]], <vscale x 8 x i1> [[TMP1]], <vscale x 8 x i1> zeroinitializer
; CHECK-NEXT: ret <vscale x 8 x i1> [[TMP2]]
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> %a)
>From 0f7c180088560f12e7ab91c68ec7dc48205b3f67 Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Thu, 23 Jul 2026 09:46:15 +0000
Subject: [PATCH 3/5] Remove CreateConvertFromSVBool.
---
.../Target/AArch64/AArch64TargetTransformInfo.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 26a9f11710546..b5d4214ee5f5a 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2019,10 +2019,8 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
auto m_ConvertToSVBool = [](auto P) {
return m_Intrinsic<Intrinsic::aarch64_sve_convert_to_svbool>(P);
};
- auto CreateConvertFromSVBool = [&IC](Type *Ty, Value *V) {
- unsigned IID = Intrinsic::aarch64_sve_convert_from_svbool;
- return IC.Builder.CreateIntrinsic(IID, Ty, V);
- };
+ constexpr Intrinsic::ID ConvertFromSVBool =
+ Intrinsic::aarch64_sve_convert_from_svbool;
Type *Ty = II.getType();
Value *NarrowLHS, *RHS;
@@ -2030,7 +2028,7 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
if (match(II.getOperand(0),
m_c_LogicalAnd(m_ConvertToSVBool(m_SpecificType(Ty, NarrowLHS)),
m_Value(RHS)))) {
- Value *NarrowRHS = CreateConvertFromSVBool(Ty, RHS);
+ Value *NarrowRHS = IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, RHS);
Value *NarrowAnd = IC.Builder.CreateLogicalAnd(NarrowLHS, NarrowRHS);
return IC.replaceInstUsesWith(II, NarrowAnd);
}
@@ -2062,12 +2060,14 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
return std::nullopt;
SmallVector<Value *> NarrowedBinOpArgs = {PredOp};
- Value *NarrowBinOpOp1 = CreateConvertFromSVBool(Ty, BinOpOp1);
+ Value *NarrowBinOpOp1 =
+ IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp1);
NarrowedBinOpArgs.push_back(NarrowBinOpOp1);
if (BinOpOp1 == BinOpOp2)
NarrowedBinOpArgs.push_back(NarrowBinOpOp1);
else
- NarrowedBinOpArgs.push_back(CreateConvertFromSVBool(Ty, BinOpOp2));
+ NarrowedBinOpArgs.push_back(
+ IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp2));
Value *NarrowedBinOp =
IC.Builder.CreateIntrinsic(IntrinsicID, Ty, NarrowedBinOpArgs);
>From 48e44ed649666e38872b33f76757788b3fb9e54a Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Thu, 23 Jul 2026 09:54:58 +0000
Subject: [PATCH 4/5] Remove NarrowedBinOpArgs.
---
.../AArch64/AArch64TargetTransformInfo.cpp | 24 ++++++++-----------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index b5d4214ee5f5a..79c681ada1599 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2037,8 +2037,8 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
if (!BinOp)
return std::nullopt;
- Intrinsic::ID IntrinsicID = BinOp->getIntrinsicID();
- switch (IntrinsicID) {
+ Intrinsic::ID BinOpIID = BinOp->getIntrinsicID();
+ switch (BinOpIID) {
case Intrinsic::aarch64_sve_and_z:
case Intrinsic::aarch64_sve_bic_z:
case Intrinsic::aarch64_sve_eor_z:
@@ -2055,22 +2055,18 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
Value *BinOpOp1 = BinOp->getOperand(1);
Value *BinOpOp2 = BinOp->getOperand(2);
- Value *PredOp;
- if (!match(BinOpPred, m_ConvertToSVBool(m_SpecificType(Ty, PredOp))))
+ Value *NarrowBinOpPred;
+ if (!match(BinOpPred, m_ConvertToSVBool(m_SpecificType(Ty, NarrowBinOpPred))))
return std::nullopt;
- SmallVector<Value *> NarrowedBinOpArgs = {PredOp};
Value *NarrowBinOpOp1 =
IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp1);
- NarrowedBinOpArgs.push_back(NarrowBinOpOp1);
- if (BinOpOp1 == BinOpOp2)
- NarrowedBinOpArgs.push_back(NarrowBinOpOp1);
- else
- NarrowedBinOpArgs.push_back(
- IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp2));
-
- Value *NarrowedBinOp =
- IC.Builder.CreateIntrinsic(IntrinsicID, Ty, NarrowedBinOpArgs);
+ Value *NarrowedBinOp2 =
+ BinOpOp1 == BinOpOp2
+ ? NarrowBinOpOp1
+ : IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp2);
+ Value *NarrowedBinOp = IC.Builder.CreateIntrinsic(
+ BinOpIID, Ty, {NarrowBinOpPred, NarrowBinOpOp1, NarrowedBinOp2});
return IC.replaceInstUsesWith(II, NarrowedBinOp);
}
>From 16a2e80b83a05ac8a54ef342595a670ce3c12807 Mon Sep 17 00:00:00 2001
From: Paul Walker <paul.walker at arm.com>
Date: Thu, 23 Jul 2026 11:55:17 +0000
Subject: [PATCH 5/5] Added dedicated matching for commuted operands to prevent
poison propagation.
---
.../AArch64/AArch64TargetTransformInfo.cpp | 16 ++++++++++++----
.../AArch64/sve-intrinsic-to-svbool-binops.ll | 2 +-
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 79c681ada1599..db92f23b33131 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2023,12 +2023,20 @@ tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II) {
Intrinsic::aarch64_sve_convert_from_svbool;
Type *Ty = II.getType();
- Value *NarrowLHS, *RHS;
+ Value *LHS, *RHS, *NarrowLHS, *NarrowRHS;
if (match(II.getOperand(0),
- m_c_LogicalAnd(m_ConvertToSVBool(m_SpecificType(Ty, NarrowLHS)),
- m_Value(RHS)))) {
- Value *NarrowRHS = IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, RHS);
+ m_LogicalAnd(m_Value(LHS),
+ m_ConvertToSVBool(m_SpecificType(Ty, NarrowRHS))))) {
+ NarrowLHS = IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, LHS);
+ Value *NarrowAnd = IC.Builder.CreateLogicalAnd(NarrowLHS, NarrowRHS);
+ return IC.replaceInstUsesWith(II, NarrowAnd);
+ }
+
+ if (match(II.getOperand(0),
+ m_LogicalAnd(m_ConvertToSVBool(m_SpecificType(Ty, NarrowLHS)),
+ m_Value(RHS)))) {
+ NarrowRHS = IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, RHS);
Value *NarrowAnd = IC.Builder.CreateLogicalAnd(NarrowLHS, NarrowRHS);
return IC.replaceInstUsesWith(II, NarrowAnd);
}
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
index b0e57f434ceb1..351d0f408e7fa 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll
@@ -52,7 +52,7 @@ define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_lhs(<vscale x 16
define <vscale x 8 x i1> @try_combine_svbool_logical_and_poison_rhs(<vscale x 16 x i1> %a) {
; CHECK-LABEL: @try_combine_svbool_logical_and_poison_rhs(
-; CHECK-NEXT: ret <vscale x 8 x i1> poison
+; CHECK-NEXT: ret <vscale x 8 x i1> zeroinitializer
;
%t1 = tail call <vscale x 16 x i1> @llvm.aarch64.sve.convert.to.svbool.nxv8i1(<vscale x 8 x i1> poison)
%t2 = select <vscale x 16 x i1> %a, <vscale x 16 x i1> %t1, <vscale x 16 x i1> zeroinitializer
More information about the llvm-commits
mailing list