[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