[llvm] [AArch64][InstCombine] xor(cmpne) -> cmpeq (PR #207007)

Matthew Devereau via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 3 09:41:08 PDT 2026


https://github.com/MDevereau updated https://github.com/llvm/llvm-project/pull/207007

>From 38f6613ad67209a8e5d0240c7d8d41f59177d97b Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Wed, 1 Jul 2026 14:13:50 +0000
Subject: [PATCH 1/4] [AArch64][InstCombine] Fold xor(cmpne(pg, v, 0), pg) into
 cmpeq(pv, v, 0)

Created after initially trying as a DAGCombine in #206931.
---
 .../AArch64/AArch64TargetTransformInfo.cpp    | 35 ++++++++
 .../AArch64/sve-intrinsic-opts-cmpne.ll       | 84 +++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index edd95625e13ea..9b58ced8d0724 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2142,10 +2142,45 @@ static std::optional<Instruction *> instCombineSVEDupX(InstCombiner &IC,
   return IC.replaceInstUsesWith(II, Splat);
 }
 
+static std::optional<Instruction *> instCombineXorSVECmpNE(InstCombiner &IC,
+                                                           IntrinsicInst &II) {
+  if (!match(II.getOperand(2), m_Zero()) || !II.hasOneUse())
+    return std::nullopt;
+
+  auto *User = dyn_cast<Instruction>(*II.user_begin());
+  if (!User ||
+      (!match(User, m_Xor(m_Specific(&II), m_Specific(II.getOperand(0)))) &&
+       !match(User, m_Xor(m_Specific(II.getOperand(0)), m_Specific(&II)))))
+    return std::nullopt;
+
+  IC.Builder.SetInsertPoint(User);
+  Intrinsic::ID IID;
+  switch ((II.getIntrinsicID())) {
+  case Intrinsic::aarch64_sve_cmpne:
+    IID = Intrinsic::aarch64_sve_cmpeq;
+    break;
+  case Intrinsic::aarch64_sve_cmpne_wide:
+    IID = Intrinsic::aarch64_sve_cmpeq_wide;
+    break;
+  default:
+    return std::nullopt;
+  }
+
+  Value *CMPEQ = IC.Builder.CreateIntrinsic(
+      IID, II.getOperand(1)->getType(),
+      {II.getOperand(0), II.getOperand(1), II.getOperand(2)});
+  CMPEQ->takeName(User);
+  IC.replaceInstUsesWith(*User, CMPEQ);
+  return IC.eraseInstFromFunction(*User);
+}
+
 static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,
                                                         IntrinsicInst &II) {
   LLVMContext &Ctx = II.getContext();
 
+  if (auto Res = instCombineXorSVECmpNE(IC, II))
+    return *Res;
+
   if (!isAllActivePredicate(II.getArgOperand(0)))
     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 bb3b3d069c7d1..dd6a11b07b7a1 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
@@ -202,6 +202,88 @@ define <vscale x 2 x i1> @dupq_d_d() #0 {
   ret <vscale x 2 x i1> %5
 }
 
+define <vscale x 16 x i1> @not_cmpne(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[NOT]]
+;
+  %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  %not = xor <vscale x 16 x i1> %cmp, %pg
+  ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpne_true(<vscale x 16 x i8> %vec) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_true(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[NOT]]
+;
+  %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> %vec, <vscale x 16 x i8> zeroinitializer)
+  %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_cmpne_swapped_xor(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_swapped_xor(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[NOT]]
+;
+  %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  %not = xor <vscale x 16 x i1> %pg, %cmp
+  ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpne_wide(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_wide(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.wide.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 2 x i64> zeroinitializer)
+; CHECK-NEXT:    ret <vscale x 16 x i1> [[NOT]]
+;
+  %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 2 x i64> zeroinitializer)
+  %not = xor <vscale x 16 x i1> %cmp, %pg
+  ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpne_nonzero_rhs(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_nonzero_rhs(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> splat (i8 1))
+; 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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> splat (i8 1))
+  %not = xor <vscale x 16 x i1> %cmp, %pg
+  ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpne_multiple_uses(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_multiple_uses(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; CHECK-NEXT:    call void @use_nxv16i1(<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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  call void @use_nxv16i1(<vscale x 16 x i1> %cmp)
+  %not = xor <vscale x 16 x i1> %cmp, %pg
+  ret <vscale x 16 x i1> %not
+}
+
+define <vscale x 16 x i1> @not_cmpne_wrong_xor_operand(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_wrong_xor_operand(
+; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT:    [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; 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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  %not = xor <vscale x 16 x i1> %cmp, splat (i1 true)
+  ret <vscale x 16 x i1> %not
+}
+
 ; Cases that cannot be converted
 
 define <vscale x 2 x i1> @dupq_neg1() #0 {
@@ -451,4 +533,6 @@ declare <vscale x 2 x i1> @llvm.aarch64.sve.cmpne.nxv2i64(<vscale x 2 x i1>, <vs
 
 declare <vscale x 2 x i64> @llvm.aarch64.sve.dup.x.nxv2i64(i64)
 
+declare void @use_nxv16i1(<vscale x 16 x i1>)
+
 attributes #0 = { "target-features"="+sve" }

>From aaee4b04bb0b5d639c8b1a7d9c9a1a75f5b9c60f Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Thu, 2 Jul 2026 11:09:08 +0000
Subject: [PATCH 2/4] address review comments

---
 .../Target/AArch64/AArch64TargetTransformInfo.cpp    | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 9b58ced8d0724..4d5adbacfab3a 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2147,13 +2147,10 @@ static std::optional<Instruction *> instCombineXorSVECmpNE(InstCombiner &IC,
   if (!match(II.getOperand(2), m_Zero()) || !II.hasOneUse())
     return std::nullopt;
 
-  auto *User = dyn_cast<Instruction>(*II.user_begin());
-  if (!User ||
-      (!match(User, m_Xor(m_Specific(&II), m_Specific(II.getOperand(0)))) &&
-       !match(User, m_Xor(m_Specific(II.getOperand(0)), m_Specific(&II)))))
+  auto *User = cast<Instruction>(*II.user_begin());
+  if (!match(User, m_c_Xor(m_Specific(&II), m_Specific(II.getOperand(0)))))
     return std::nullopt;
 
-  IC.Builder.SetInsertPoint(User);
   Intrinsic::ID IID;
   switch ((II.getIntrinsicID())) {
   case Intrinsic::aarch64_sve_cmpne:
@@ -2166,12 +2163,13 @@ static std::optional<Instruction *> instCombineXorSVECmpNE(InstCombiner &IC,
     return std::nullopt;
   }
 
+  IC.Builder.SetInsertPoint(User);
   Value *CMPEQ = IC.Builder.CreateIntrinsic(
       IID, II.getOperand(1)->getType(),
       {II.getOperand(0), II.getOperand(1), II.getOperand(2)});
-  CMPEQ->takeName(User);
   IC.replaceInstUsesWith(*User, CMPEQ);
-  return IC.eraseInstFromFunction(*User);
+  IC.eraseInstFromFunction(*User);
+  return &II;
 }
 
 static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,

>From 8bda6e668e694207a334a8ce50aafdaf92e15b6d Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Fri, 3 Jul 2026 08:07:16 +0000
Subject: [PATCH 3/4] remove zero constraint

---
 .../AArch64/AArch64TargetTransformInfo.cpp    |  7 +-
 .../AArch64/sve-intrinsic-opts-cmpne.ll       | 69 ++++++-------------
 2 files changed, 26 insertions(+), 50 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 4d5adbacfab3a..5c60a5f0c4013 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2142,17 +2142,18 @@ static std::optional<Instruction *> instCombineSVEDupX(InstCombiner &IC,
   return IC.replaceInstUsesWith(II, Splat);
 }
 
+// xor(cmpne(%pg, %lhs, %rhs), %pg)
+// -> cmpeq(%pg, %lhs, %rhs)
 static std::optional<Instruction *> instCombineXorSVECmpNE(InstCombiner &IC,
                                                            IntrinsicInst &II) {
-  if (!match(II.getOperand(2), m_Zero()) || !II.hasOneUse())
+  if (!II.hasOneUse())
     return std::nullopt;
-
   auto *User = cast<Instruction>(*II.user_begin());
   if (!match(User, m_c_Xor(m_Specific(&II), m_Specific(II.getOperand(0)))))
     return std::nullopt;
 
   Intrinsic::ID IID;
-  switch ((II.getIntrinsicID())) {
+  switch (II.getIntrinsicID()) {
   case Intrinsic::aarch64_sve_cmpne:
     IID = Intrinsic::aarch64_sve_cmpeq;
     break;
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 dd6a11b07b7a1..e803572a06523 100644
--- a/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
+++ b/llvm/test/Transforms/InstCombine/AArch64/sve-intrinsic-opts-cmpne.ll
@@ -202,84 +202,61 @@ define <vscale x 2 x i1> @dupq_d_d() #0 {
   ret <vscale x 2 x i1> %5
 }
 
-define <vscale x 16 x i1> @not_cmpne(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+define <vscale x 16 x i1> @not_cmpne(<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_cmpne(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; 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.cmpeq.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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  %cmp = 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)
   %not = xor <vscale x 16 x i1> %cmp, %pg
   ret <vscale x 16 x i1> %not
 }
 
-define <vscale x 16 x i1> @not_cmpne_true(<vscale x 16 x i8> %vec) #0 {
-; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_true(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> splat (i1 true), <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
-; CHECK-NEXT:    ret <vscale x 16 x i1> [[NOT]]
-;
-  %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> %vec, <vscale x 16 x i8> zeroinitializer)
-  %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_cmpne_swapped_xor(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+define <vscale x 16 x i1> @not_cmpne_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_cmpne_swapped_xor(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; 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.cmpeq.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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  %cmp = 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)
   %not = xor <vscale x 16 x i1> %pg, %cmp
   ret <vscale x 16 x i1> %not
 }
 
-define <vscale x 16 x i1> @not_cmpne_wide(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+define <vscale x 16 x i1> @not_cmpne_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_cmpne_wide(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[NOT:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpeq.wide.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 2 x i64> zeroinitializer)
-; CHECK-NEXT:    ret <vscale x 16 x i1> [[NOT]]
-;
-  %cmp = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.wide.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 2 x i64> zeroinitializer)
-  %not = xor <vscale x 16 x i1> %cmp, %pg
-  ret <vscale x 16 x i1> %not
-}
-
-define <vscale x 16 x i1> @not_cmpne_nonzero_rhs(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
-; CHECK-LABEL: define <vscale x 16 x i1> @not_cmpne_nonzero_rhs(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> splat (i8 1))
-; CHECK-NEXT:    [[NOT:%.*]] = xor <vscale x 16 x i1> [[CMP]], [[PG]]
+; 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.cmpeq.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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> splat (i8 1))
+  %cmp = 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)
   %not = xor <vscale x 16 x i1> %cmp, %pg
   ret <vscale x 16 x i1> %not
 }
 
-define <vscale x 16 x i1> @not_cmpne_multiple_uses(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+define <vscale x 16 x i1> @not_cmpne_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_cmpne_multiple_uses(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
-; CHECK-NEXT:    call void @use_nxv16i1(<vscale x 16 x i1> [[CMP]])
+; 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.cmpne.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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
-  call void @use_nxv16i1(<vscale x 16 x i1> %cmp)
+  %cmp = 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)
+  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
 }
 
-define <vscale x 16 x i1> @not_cmpne_wrong_xor_operand(<vscale x 16 x i8> %vec, <vscale x 16 x i1> %pg) #0 {
+define <vscale x 16 x i1> @not_cmpne_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_cmpne_wrong_xor_operand(
-; CHECK-SAME: <vscale x 16 x i8> [[VEC:%.*]], <vscale x 16 x i1> [[PG:%.*]]) #[[ATTR0]] {
-; CHECK-NEXT:    [[CMP:%.*]] = call <vscale x 16 x i1> @llvm.aarch64.sve.cmpne.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[VEC]], <vscale x 16 x i8> zeroinitializer)
+; 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.cmpne.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.cmpne.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %vec, <vscale x 16 x i8> zeroinitializer)
+  %cmp = 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)
   %not = xor <vscale x 16 x i1> %cmp, splat (i1 true)
   ret <vscale x 16 x i1> %not
 }
@@ -533,6 +510,4 @@ declare <vscale x 2 x i1> @llvm.aarch64.sve.cmpne.nxv2i64(<vscale x 2 x i1>, <vs
 
 declare <vscale x 2 x i64> @llvm.aarch64.sve.dup.x.nxv2i64(i64)
 
-declare void @use_nxv16i1(<vscale x 16 x i1>)
-
 attributes #0 = { "target-features"="+sve" }

>From 2aa0071d117c3230093d12cf288fad9e1d93914a Mon Sep 17 00:00:00 2001
From: Matt Devereau <matthew.devereau at arm.com>
Date: Fri, 3 Jul 2026 08:44:07 +0000
Subject: [PATCH 4/4] Remove unnecessary *

---
 llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 5c60a5f0c4013..b7d8a8ff4657b 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -2178,7 +2178,7 @@ static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,
   LLVMContext &Ctx = II.getContext();
 
   if (auto Res = instCombineXorSVECmpNE(IC, II))
-    return *Res;
+    return Res;
 
   if (!isAllActivePredicate(II.getArgOperand(0)))
     return std::nullopt;



More information about the llvm-commits mailing list