[llvm] [LLVM][InstCombine] Enable simplification of SVE predicate binops. (PR #211016)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 21 08:51:02 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Paul Walker (paulwalker-arm)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/211016.diff
2 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp (+46-21)
- (modified) llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-to-svbool-binops.ll (+5-7)
``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 9d448b4a8681a..83562c17092e9 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -1719,7 +1719,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:
@@ -1728,13 +1727,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:
@@ -1803,6 +1800,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:
@@ -1928,6 +1935,13 @@ simplifySVEIntrinsicBinOp(InstCombiner &IC, IntrinsicInst &II,
if (IInfo.inactiveLanesAreNotDefined())
return IC.replaceInstUsesWith(II, SimpleII);
+ if (IInfo.resultIsZeroInitialized()) {
+ // Inactive lanes must be zero'd.
+ Value *InactiveLanes = Constant::getNullValue(II.getType());
+ SimpleII = IC.Builder.CreateSelect(Pg, SimpleII, InactiveLanes);
+ return IC.replaceInstUsesWith(II, SimpleII);
+ }
+
Value *Inactive = II.getOperand(IInfo.getOperandIdxInactiveLanesTakenFrom());
// The intrinsic does nothing (e.g. sve.mul(pg, A, 1.0)).
@@ -1998,11 +2012,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:
@@ -2016,32 +2049,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 abe1ed0fa37b8..fcb9b771a0a54 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)
@@ -43,7 +43,7 @@ define <vscale x 4 x i1> @try_combine_svbool_binop_and_2(<vscale x 4 x i1> %a, <
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)
@@ -66,9 +66,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)
@@ -115,7 +113,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)
``````````
</details>
https://github.com/llvm/llvm-project/pull/211016
More information about the llvm-commits
mailing list