[llvm] 250a554 - [AArch64][InstCombine] Fold xor(cmpeq, pg) to cmpne (#207759)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 7 07:20:21 PDT 2026
Author: Matthew Devereau
Date: 2026-07-07T15:20:15+01:00
New Revision: 250a554f05e54f2bf4f2c2ba736ed2e06429aba2
URL: https://github.com/llvm/llvm-project/commit/250a554f05e54f2bf4f2c2ba736ed2e06429aba2
DIFF: https://github.com/llvm/llvm-project/commit/250a554f05e54f2bf4f2c2ba736ed2e06429aba2.diff
LOG: [AArch64][InstCombine] Fold xor(cmpeq, pg) to cmpne (#207759)
Extend the existing xor(cmpne(pg, lhs, rhs), pg) fold to also handle
cmpeq to cmpne
Added:
llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpeq.ll
Modified:
llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index ad55d46d4c202..4712c416450ba 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2144,7 +2144,7 @@ static std::optional<Instruction *> instCombineSVEDupX(InstCombiner &IC,
// xor(cmpne(%pg, %lhs, %rhs), %pg)
// -> cmpeq(%pg, %lhs, %rhs)
-static std::optional<Instruction *> instCombineXorSVECmpNE(InstCombiner &IC,
+static std::optional<Instruction *> instCombineXorSVECmpCC(InstCombiner &IC,
IntrinsicInst &II) {
if (!II.hasOneUse())
return std::nullopt;
@@ -2160,15 +2160,21 @@ static std::optional<Instruction *> instCombineXorSVECmpNE(InstCombiner &IC,
case Intrinsic::aarch64_sve_cmpne_wide:
IID = Intrinsic::aarch64_sve_cmpeq_wide;
break;
+ case Intrinsic::aarch64_sve_cmpeq:
+ IID = Intrinsic::aarch64_sve_cmpne;
+ break;
+ case Intrinsic::aarch64_sve_cmpeq_wide:
+ IID = Intrinsic::aarch64_sve_cmpne_wide;
+ break;
default:
return std::nullopt;
}
IC.Builder.SetInsertPoint(User);
- Value *CMPEQ = IC.Builder.CreateIntrinsic(
+ Value *CMPCC = IC.Builder.CreateIntrinsic(
IID, II.getOperand(1)->getType(),
{II.getOperand(0), II.getOperand(1), II.getOperand(2)});
- IC.replaceInstUsesWith(*User, CMPEQ);
+ IC.replaceInstUsesWith(*User, CMPCC);
IC.eraseInstFromFunction(*User);
return &II;
}
@@ -2177,7 +2183,7 @@ static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,
IntrinsicInst &II) {
LLVMContext &Ctx = II.getContext();
- if (auto Res = instCombineXorSVECmpNE(IC, II))
+ if (auto Res = instCombineXorSVECmpCC(IC, II))
return Res;
if (!isAllActivePredicate(II.getArgOperand(0)))
@@ -3182,6 +3188,9 @@ AArch64TTIImpl::instCombineIntrinsic(InstCombiner &IC,
return instCombineSVEDup(IC, II);
case Intrinsic::aarch64_sve_dup_x:
return instCombineSVEDupX(IC, II);
+ case Intrinsic::aarch64_sve_cmpeq:
+ case Intrinsic::aarch64_sve_cmpeq_wide:
+ return instCombineXorSVECmpCC(IC, II);
case Intrinsic::aarch64_sve_cmpne:
case Intrinsic::aarch64_sve_cmpne_wide:
return instCombineSVECmpNE(IC, II);
diff --git a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpeq.ll b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpeq.ll
new file mode 100644
index 0000000000000..c472a8af0f506
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpeq.ll
@@ -0,0 +1,67 @@
+; 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"
+
+define <vscale x 16 x i1> @not_cmpeq(<vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpeq(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC_A:%.*]], <vscale x 16 x i8> [[VEC_B:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC_A]], <vscale x 16 x i8> [[VEC_B]])
+; CHECK-NEXT: ret <vscale x 16 x i1> [[NOT]]
+;
+ %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b)
+ %not = xor <vscale x 16 x i1> %cmp, %pg
+ ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpeq_swapped_xor(<vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpeq_swapped_xor(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC_A:%.*]], <vscale x 16 x i8> [[VEC_B:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC_A]], <vscale x 16 x i8> [[VEC_B]])
+; CHECK-NEXT: ret <vscale x 16 x i1> [[NOT]]
+;
+ %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b)
+ %not = xor <vscale x 16 x i1> %pg, %cmp
+ ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpeq_wide(<vscale x 16 x i8> %vec_a, <vscale x 2 x i64> %vec_b, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpeq_wide(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC_A:%.*]], <vscale x 2 x i64> [[VEC_B:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.wide.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC_A]], <vscale x 2 x i64> [[VEC_B]])
+; CHECK-NEXT: ret <vscale x 16 x i1> [[NOT]]
+;
+ %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec_a, <vscale x 2 x i64> %vec_b)
+ %not = xor <vscale x 16 x i1> %cmp, %pg
+ ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpeq_wrong_xor_operand(<vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpeq_wrong_xor_operand(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC_A:%.*]], <vscale x 16 x i8> [[VEC_B:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC_A]], <vscale x 16 x i8> [[VEC_B]])
+; CHECK-NEXT: [[NOT:%.*]] = xor <vscale x 16 x i1> [[CMP]], splat (i1 true)
+; CHECK-NEXT: ret <vscale x 16 x i1> [[NOT]]
+;
+ %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b)
+ %not = xor <vscale x 16 x i1> %cmp, splat (i1 true)
+ ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpeq_multiple_uses(<vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpeq_multiple_uses(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC_A:%.*]], <vscale x 16 x i8> [[VEC_B:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC_A]], <vscale x 16 x i8> [[VEC_B]])
+; CHECK-NEXT: call void (...) @llvm.fake.use(<vscale x 16 x i1> [[CMP]])
+; CHECK-NEXT: [[NOT:%.*]] = xor <vscale x 16 x i1> [[CMP]], [[PG]]
+; CHECK-NEXT: ret <vscale x 16 x i1> [[NOT]]
+;
+ %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec_a, <vscale x 16 x i8> %vec_b)
+ call void (...) @llvm.fake.use(<vscale x 16 x i1> %cmp)
+ %not = xor <vscale x 16 x i1> %cmp, %pg
+ ret <vscale x 16 x i1> %not
+}
+
+declare <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.wide.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>, <vscale x 2 x i64>)
+
+attributes #0 = { "target-features"="+sve" }
More information about the llvm-commits
mailing list