[llvm] 59691a1 - [LLVM][InstCombine] Add simplification of SVE compare intrinsics. (#211249)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 30 03:22:47 PDT 2026
Author: Paul Walker
Date: 2026-07-30T11:22:43+01:00
New Revision: 59691a1f7c907cc492a62ebded8521535974d25a
URL: https://github.com/llvm/llvm-project/commit/59691a1f7c907cc492a62ebded8521535974d25a
DIFF: https://github.com/llvm/llvm-project/commit/59691a1f7c907cc492a62ebded8521535974d25a.diff
LOG: [LLVM][InstCombine] Add simplification of SVE compare intrinsics. (#211249)
Extends SVEIntrinsicInfo to accept LLVM IR compare information, which is
then used to call simplifyCmpInst on the data operands of SVE compare
intrinsic calls.
Added:
llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-simplify-cmp.ll
Modified:
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 207080ba7c971..fa48d97fd8d66 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -1431,6 +1431,28 @@ struct SVEIntrinsicInfo {
return *this;
}
+ bool hasCmpPredicate() const {
+ return CmpPredicate != CmpInst::BAD_ICMP_PREDICATE;
+ }
+
+ CmpInst::Predicate getCmpPredicate() const {
+ assert(hasCmpPredicate() && "Property not set!");
+ return CmpPredicate;
+ }
+
+ SVEIntrinsicInfo &setCmpPredicate(CmpInst::Predicate Pred) {
+ assert(!hasCmpPredicate() && "Cannot set property twice!");
+ CmpPredicate = Pred;
+
+ if (CmpInst::isFPPredicate(Pred))
+ return setMatchingIROpcode(Instruction::FCmp);
+
+ if (CmpInst::isIntPredicate(Pred))
+ return setMatchingIROpcode(Instruction::ICmp);
+
+ llvm_unreachable("Unsupported compare predicate!");
+ }
+
//
// Properties relating to the result of inactive lanes.
//
@@ -1507,6 +1529,7 @@ struct SVEIntrinsicInfo {
Intrinsic::ID UndefIntrinsic = Intrinsic::not_intrinsic;
unsigned IROpcode = 0;
+ CmpInst::Predicate CmpPredicate = CmpInst::BAD_ICMP_PREDICATE;
enum PredicationStyle {
Uninitialized,
@@ -1755,29 +1778,8 @@ static SVEIntrinsicInfo constructSVEIntrinsicInfo(IntrinsicInst &II) {
case Intrinsic::aarch64_sve_uaddv:
case Intrinsic::aarch64_sve_umaxv:
case Intrinsic::aarch64_sve_umaxqv:
- case Intrinsic::aarch64_sve_cmpeq:
- case Intrinsic::aarch64_sve_cmpeq_wide:
- case Intrinsic::aarch64_sve_cmpge:
- case Intrinsic::aarch64_sve_cmpge_wide:
- case Intrinsic::aarch64_sve_cmpgt:
- case Intrinsic::aarch64_sve_cmpgt_wide:
- case Intrinsic::aarch64_sve_cmphi:
- case Intrinsic::aarch64_sve_cmphi_wide:
- case Intrinsic::aarch64_sve_cmphs:
- case Intrinsic::aarch64_sve_cmphs_wide:
- case Intrinsic::aarch64_sve_cmple_wide:
- case Intrinsic::aarch64_sve_cmplo_wide:
- case Intrinsic::aarch64_sve_cmpls_wide:
- case Intrinsic::aarch64_sve_cmplt_wide:
- case Intrinsic::aarch64_sve_cmpne:
- case Intrinsic::aarch64_sve_cmpne_wide:
case Intrinsic::aarch64_sve_facge:
case Intrinsic::aarch64_sve_facgt:
- case Intrinsic::aarch64_sve_fcmpeq:
- case Intrinsic::aarch64_sve_fcmpge:
- case Intrinsic::aarch64_sve_fcmpgt:
- case Intrinsic::aarch64_sve_fcmpne:
- case Intrinsic::aarch64_sve_fcmpuo:
case Intrinsic::aarch64_sve_ld1:
case Intrinsic::aarch64_sve_ld1_gather:
case Intrinsic::aarch64_sve_ld1_gather_index:
@@ -1825,6 +1827,58 @@ static SVEIntrinsicInfo constructSVEIntrinsicInfo(IntrinsicInst &II) {
return SVEIntrinsicInfo::defaultZeroingOp().setMatchingIROpcode(
Instruction::Xor);
+ case Intrinsic::aarch64_sve_cmpeq:
+ case Intrinsic::aarch64_sve_cmpeq_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_EQ);
+ case Intrinsic::aarch64_sve_cmpge:
+ case Intrinsic::aarch64_sve_cmpge_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_SGE);
+ case Intrinsic::aarch64_sve_cmpgt:
+ case Intrinsic::aarch64_sve_cmpgt_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_SGT);
+ case Intrinsic::aarch64_sve_cmphi:
+ case Intrinsic::aarch64_sve_cmphi_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_UGT);
+ case Intrinsic::aarch64_sve_cmphs:
+ case Intrinsic::aarch64_sve_cmphs_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_UGE);
+ case Intrinsic::aarch64_sve_cmple_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_SLE);
+ case Intrinsic::aarch64_sve_cmplo_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_ULT);
+ case Intrinsic::aarch64_sve_cmpls_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_ULE);
+ case Intrinsic::aarch64_sve_cmplt_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_SLT);
+ case Intrinsic::aarch64_sve_cmpne:
+ case Intrinsic::aarch64_sve_cmpne_wide:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::ICMP_NE);
+ case Intrinsic::aarch64_sve_fcmpeq:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::FCMP_OEQ);
+ case Intrinsic::aarch64_sve_fcmpge:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::FCMP_OGE);
+ case Intrinsic::aarch64_sve_fcmpgt:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::FCMP_OGT);
+ case Intrinsic::aarch64_sve_fcmpne:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::FCMP_UNE);
+ case Intrinsic::aarch64_sve_fcmpuo:
+ return SVEIntrinsicInfo::defaultZeroingOp().setCmpPredicate(
+ CmpInst::FCMP_UNO);
+
case Intrinsic::aarch64_sve_prf:
case Intrinsic::aarch64_sve_prfb_gather_index:
case Intrinsic::aarch64_sve_prfb_gather_scalar_offset:
@@ -1964,6 +2018,73 @@ simplifySVEIntrinsicBinOp(InstCombiner &IC, IntrinsicInst &II,
return IC.replaceInstUsesWith(II, SimpleII);
}
+static std::optional<Instruction *>
+simplifySVEIntrinsicCompare(InstCombiner &IC, IntrinsicInst &II,
+ const SVEIntrinsicInfo &IInfo) {
+ const unsigned Opc = IInfo.getMatchingIROpode();
+ assert((Opc == Instruction::ICmp || Opc == Instruction::FCmp) &&
+ "Expected a compare operation!");
+
+ Value *Pg = II.getOperand(0);
+ Value *LHS = II.getOperand(1);
+ Value *RHS = II.getOperand(2);
+ CmpInst::Predicate CmpPred = IInfo.getCmpPredicate();
+ bool IsWideICmp =
+ Opc == Instruction::ICmp && LHS->getType() != RHS->getType();
+ assert((IsWideICmp || LHS->getType() == RHS->getType()) &&
+ "Unexpected wide compare!");
+
+ // Canonicalise constants to the RHS.
+ if ((ICmpInst::isCommutative(CmpPred) || FCmpInst::isCommutative(CmpPred)) &&
+ isa<Constant>(LHS) && !isa<Constant>(RHS) && !IsWideICmp) {
+ IC.replaceOperand(II, 1, RHS);
+ IC.replaceOperand(II, 2, LHS);
+ return &II;
+ }
+
+ // Only active lanes matter when simplifying the operation.
+ LHS = stripInactiveLanes(LHS, Pg);
+ RHS = stripInactiveLanes(RHS, Pg);
+
+ if (IsWideICmp) {
+ // We can do more for wide compares, but not using simplifyCmpInst.
+ const APInt *LHSVal, *RHSVal;
+ if (!match(LHS, m_APInt(LHSVal)) || !match(RHS, m_APInt(RHSVal)))
+ return std::nullopt;
+
+ // Consider cmpge.wide(..., <vscale x 4 x i32> LHS, <vscale x 2 x i64> RHS),
+ // we must reconstruct the constants because LHS has the wrong element type,
+ // and RHS the wrong element count.
+ Type *WideVT = VectorType::get(RHS->getType()->getScalarType(),
+ cast<VectorType>(LHS->getType()));
+ // NOTE: Wide equality comparisons are signed.
+ if (ICmpInst::isUnsigned(CmpPred)) {
+ LHS = ConstantInt::get(WideVT, LHSVal->getZExtValue());
+ RHS = ConstantInt::get(WideVT, RHSVal->getZExtValue());
+ } else {
+ LHS = ConstantInt::get(WideVT, LHSVal->getSExtValue());
+ RHS = ConstantInt::get(WideVT, RHSVal->getSExtValue());
+ }
+ }
+
+ // TODO: Allow fast-math flags for calls to compare intrinsics.
+ const DataLayout &DL = II.getDataLayout();
+ Value *SimpleII = simplifyCmpInst(CmpPred, LHS, RHS, DL);
+
+ // No simplification happened.
+ if (!SimpleII)
+ return std::nullopt;
+
+ assert(IInfo.resultIsZeroInitialized() && "Expected a zeroing operation!");
+
+ if (match(SimpleII, m_ZeroInt()))
+ return IC.replaceInstUsesWith(II, SimpleII);
+
+ // Inactive lanes must be zeroed.
+ SimpleII = IC.Builder.CreateLogicalAnd(Pg, SimpleII);
+ return IC.replaceInstUsesWith(II, SimpleII);
+}
+
// Use SVE intrinsic info to eliminate redundant operands and/or canonicalise
// to operations with less strict inactive lane requirements.
static std::optional<Instruction *>
@@ -2004,11 +2125,21 @@ simplifySVEIntrinsic(InstCombiner &IC, IntrinsicInst &II,
}
}
+ if (!IInfo.hasMatchingIROpode())
+ return std::nullopt;
+
+ //
// Operation specific simplifications.
- if (IInfo.hasMatchingIROpode() &&
- Instruction::isBinaryOp(IInfo.getMatchingIROpode()))
+ //
+
+ unsigned Opc = IInfo.getMatchingIROpode();
+
+ if (Instruction::isBinaryOp(Opc))
return simplifySVEIntrinsicBinOp(IC, II, IInfo);
+ if (Opc == Instruction::FCmp || Opc == Instruction::ICmp)
+ return simplifySVEIntrinsicCompare(IC, II, IInfo);
+
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 11e6e0089293a..d9a5434c35269 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
@@ -275,8 +275,7 @@ define <vscale x 16 x i8> @zext_cmpne_i8(<vscale x 16 x i8> %vec) #0 {
define <vscale x 16 x i8> @zext_cmpne_zero_lhs_i8(<vscale x 16 x i8> %vec) #0 {
; CHECK-LABEL: define <vscale x 16 x i8> @zext_cmpne_zero_lhs_i8(
; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> [[VEC]])
-; CHECK-NEXT: [[ZEXT:%.*]] = zext <vscale x 16 x i1> [[TMP1]] to <vscale x 16 x i8>
+; CHECK-NEXT: [[ZEXT:%.*]] = 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> [[VEC]], <vscale x 16 x i8> splat (i8 1))
; CHECK-NEXT: ret <vscale x 16 x i8> [[ZEXT]]
;
%cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> zeroinitializer, <vscale x 16 x i8> %vec)
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-simplify-cmp.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-simplify-cmp.ll
new file mode 100644
index 0000000000000..12b0ed96cf9cc
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-simplify-cmp.ll
@@ -0,0 +1,329 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; The following tests verify the mechanics of simplification. The operation is
+; not important beyond being commutative.
+
+define <vscale x 4 x i1> @canonicalise_constant_to_rhs(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @canonicalise_constant_to_rhs(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x i32> [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.nxv4i32(<vscale x 4 x i1> [[PG]], <vscale x 4 x i32> [[A]], <vscale x 4 x i32> splat (i32 303))
+; CHECK-NEXT: ret <vscale x 4 x i1> [[R]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> %a)
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @cannot_canonicalise_constant_to_rhs_not_commutative_int(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @cannot_canonicalise_constant_to_rhs_not_commutative_int(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x i32> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpge.nxv4i32(<vscale x 4 x i1> [[PG]], <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> [[A]])
+; CHECK-NEXT: ret <vscale x 4 x i1> [[R]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpge.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> %a)
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @cannot_canonicalise_constant_to_rhs_operand_type_mismatch(<vscale x 4 x i1> %pg, <vscale x 2 x i64> %a) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @cannot_canonicalise_constant_to_rhs_operand_type_mismatch(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 2 x i64> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.wide.nxv4i32(<vscale x 4 x i1> [[PG]], <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> [[A]])
+; CHECK-NEXT: ret <vscale x 4 x i1> [[R]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> %a)
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @canonicalise_fp_constant_to_rhs(<vscale x 4 x i1> %pg, <vscale x 4 x float> %a) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @canonicalise_fp_constant_to_rhs(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpne.nxv4f32(<vscale x 4 x i1> [[PG]], <vscale x 4 x float> [[A]], <vscale x 4 x float> splat (float 5.000000e+00))
+; CHECK-NEXT: ret <vscale x 4 x i1> [[R]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpne.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float 5.0), <vscale x 4 x float> %a)
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @cannot_canonicalise_fp_constant_to_rhs_not_commutative_fp(<vscale x 4 x i1> %pg, <vscale x 4 x float> %a) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @cannot_canonicalise_fp_constant_to_rhs_not_commutative_fp(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpge.nxv4f32(<vscale x 4 x i1> [[PG]], <vscale x 4 x float> splat (float 5.000000e+00), <vscale x 4 x float> [[A]])
+; CHECK-NEXT: ret <vscale x 4 x i1> [[R]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpge.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float 5.0), <vscale x 4 x float> %a)
+ ret <vscale x 4 x i1> %r
+}
+
+; Show that we only need to know the active lanes are constant.
+define <vscale x 4 x i1> @constant_icmp_after_stripping_inactive_lanes(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a, <vscale x 4 x i32> %b) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmp_after_stripping_inactive_lanes(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x i32> [[A:%.*]], <vscale x 4 x i32> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %a.dup = call <vscale x 4 x i32> @llvm.aarch64.sve.dup.nxv4i32(<vscale x 4 x i32> %a, <vscale x 4 x i1> %pg, i32 3)
+ %b.dup = call <vscale x 4 x i32> @llvm.aarch64.sve.dup.nxv4i32(<vscale x 4 x i32> %b, <vscale x 4 x i1> %pg, i32 2)
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpgt.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a.dup, <vscale x 4 x i32> %b.dup)
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 16 x i1> @constant_icmp_due_to_range_of_type(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @constant_icmp_due_to_range_of_type(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 16 x i1> zeroinitializer
+;
+ %r = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpgt.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 16 x i8> splat (i8 127))
+ ret <vscale x 16 x i1> %r
+}
+
+; Wide compares implicitly promote the smaller typed operand to the larger type.
+define <vscale x 16 x i1> @non_constant_icmp_wide_due_to_range_of_type(<vscale x 16 x i1> %pg, <vscale x 2 x i64> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @non_constant_icmp_wide_due_to_range_of_type(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 2 x i64> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpgt.wide.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> splat (i8 127), <vscale x 2 x i64> [[A]])
+; CHECK-NEXT: ret <vscale x 16 x i1> [[R]]
+;
+ %r = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpgt.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> splat (i8 127), <vscale x 2 x i64> %a)
+ ret <vscale x 16 x i1> %r
+}
+
+; TODO: We can do better here.
+; Wide compares implicitly promote the smaller typed operand to the larger type,
+; but with the larger operand being constant we know it is too big.
+define <vscale x 16 x i1> @constant_icmp_wide_due_to_range_of_type(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @constant_icmp_wide_due_to_range_of_type(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpgt.wide.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[A]], <vscale x 2 x i64> splat (i64 127))
+; CHECK-NEXT: ret <vscale x 16 x i1> [[R]]
+;
+ %r = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpgt.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %a, <vscale x 2 x i64> splat (i64 127))
+ ret <vscale x 16 x i1> %r
+}
+
+; Ensure inactive lanes are zeroed after simplification.
+define <vscale x 4 x i1> @non_constant_simplification(<vscale x 4 x i1> %pg, <vscale x 4 x i1> %a) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @non_constant_simplification(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x i1> [[A:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[R:%.*]] = select <vscale x 4 x i1> [[PG]], <vscale x 4 x i1> [[A]], <vscale x 4 x i1> zeroinitializer
+; CHECK-NEXT: ret <vscale x 4 x i1> [[R]]
+;
+ %a.ext = zext <vscale x 4 x i1> %a to <vscale x 4 x i32>
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> %a.ext, <vscale x 4 x i32> splat (i32 0))
+ ret <vscale x 4 x i1> %r
+}
+
+; Unlike regular equality comparisons, the wide variant is explicitly signed.
+define <vscale x 16 x i1> @constant_icmpeq_wide_is_signed(<vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @constant_icmpeq_wide_is_signed(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 16 x i1> [[PG]]
+;
+ %r = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> splat (i8 -1), <vscale x 2 x i64> splat (i64 -1))
+ ret <vscale x 16 x i1> %r
+}
+
+; Unlike regular equality comparisons, the wide variant is explicitly signed.
+define <vscale x 16 x i1> @constant_icmpne_wide_is_signed(<vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @constant_icmpne_wide_is_signed(
+; CHECK-SAME: <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 16 x i1> [[PG]]
+;
+ %r = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> splat (i8 -1), <vscale x 2 x i64> splat (i64 255))
+ ret <vscale x 16 x i1> %r
+}
+
+; The following tests demonstrate the operations for which hooks are in place to
+; enable simplification. Given the simplications themselves are common code, it
+; is assumed they are already well tested elsewhere.
+
+define <vscale x 4 x i1> @constant_fcmpeq(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_fcmpeq(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpeq.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float 5.0), <vscale x 4 x float> splat (float 3.0))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_fcmpge(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_fcmpge(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpge.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float 5.0), <vscale x 4 x float> splat (float 3.0))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_fcmpgt(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_fcmpgt(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpgt.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float -5.0), <vscale x 4 x float> splat (float 3.0))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_fcmpne(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_fcmpne(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpne.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float 5.0), <vscale x 4 x float> splat (float 3.0))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_fcmpuo(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_fcmpuo(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.fcmpuo.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> splat (float 5.0), <vscale x 4 x float> splat (float 3.0))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpeq(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpeq(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpeq.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> splat (i32 777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpeq_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpeq_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpeq.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpge(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpge(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpge.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 -303), <vscale x 4 x i32> splat (i32 777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpge_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpge_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpge.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpgt(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpgt(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpgt.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> splat (i32 -777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpgt_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpgt_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpgt.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 -303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmphi(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmphi(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmphi.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> splat (i32 777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmphi_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmphi_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmphi.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmphs(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmphs(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmphs.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> splat (i32 777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmphs_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmphs_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmphs.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmple_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmple_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmple.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 -303), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmplo_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmplo_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmplo.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 777), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpls_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpls_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpls.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmplt_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmplt_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmplt.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 -303))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpne(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpne(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> [[PG]]
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 4 x i32> splat (i32 777))
+ ret <vscale x 4 x i1> %r
+}
+
+define <vscale x 4 x i1> @constant_icmpne_wide(<vscale x 4 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 4 x i1> @constant_icmpne_wide(
+; CHECK-SAME: <vscale x 4 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: ret <vscale x 4 x i1> zeroinitializer
+;
+ %r = call <vscale x 4 x i1> @llvm.aarch64.sve.cmpne.wide.nxv4i32(<vscale x 4 x i1> %pg, <vscale x 4 x i32> splat (i32 303), <vscale x 2 x i64> splat (i64 303))
+ ret <vscale x 4 x i1> %r
+}
+
+attributes #0 = { "target-features"="+sve" }
More information about the llvm-commits
mailing list