[llvm] [SDAG] Allow S/Zext in select-abd pattern (PR #191207)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 15 02:42:40 PDT 2026


https://github.com/DaKnig updated https://github.com/llvm/llvm-project/pull/191207

>From bc4853c87b50021b72621cf39b242383ce5225d8 Mon Sep 17 00:00:00 2001
From: DaKnig <ZannyKnig at disroot.org>
Date: Thu, 9 Apr 2026 17:39:28 +0300
Subject: [PATCH 1/2] lit

---
 llvm/test/CodeGen/AArch64/abd-combine.ll | 79 ++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/llvm/test/CodeGen/AArch64/abd-combine.ll b/llvm/test/CodeGen/AArch64/abd-combine.ll
index cdb40ceb46b1e..6d021ae0f48a9 100644
--- a/llvm/test/CodeGen/AArch64/abd-combine.ll
+++ b/llvm/test/CodeGen/AArch64/abd-combine.ll
@@ -523,6 +523,85 @@ define <1 x i64> @recursive() {
   ret <1 x i64> %10
 }
 
+define <4 x i32> @abd_select_sext(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: abd_select_sext:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    cmgt v2.4h, v1.4h, v0.4h
+; CHECK-NEXT:    ssubl v3.4s, v0.4h, v1.4h
+; CHECK-NEXT:    ssubl v0.4s, v1.4h, v0.4h
+; CHECK-NEXT:    sshll v2.4s, v2.4h, #0
+; CHECK-NEXT:    bif v0.16b, v3.16b, v2.16b
+; CHECK-NEXT:    ret
+  %conv = sext <4 x i16> %a to <4 x i32>
+  %conv1 = sext <4 x i16> %b to <4 x i32>
+  %sub.i = sub nsw <4 x i32> %conv, %conv1
+  %cmp.i = icmp sgt <4 x i16> %b, %a
+  %sub1.i = sub nsw <4 x i32> %conv1, %conv
+  %spec.select.i = select <4 x i1> %cmp.i, <4 x i32> %sub1.i, <4 x i32> %sub.i
+  ret <4 x i32> %spec.select.i
+}
+
+define <4 x i32> @abd_select_sext_add(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: abd_select_sext_add:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    cmgt v3.4h, v1.4h, v0.4h
+; CHECK-NEXT:    ssubl v4.4s, v0.4h, v1.4h
+; CHECK-NEXT:    ssubl v0.4s, v1.4h, v0.4h
+; CHECK-NEXT:    movi v2.4s, #19
+; CHECK-NEXT:    sshll v3.4s, v3.4h, #0
+; CHECK-NEXT:    bif v0.16b, v4.16b, v3.16b
+; CHECK-NEXT:    add v0.4s, v0.4s, v2.4s
+; CHECK-NEXT:    ret
+  %conv = sext <4 x i16> %a to <4 x i32>
+  %conv1 = sext <4 x i16> %b to <4 x i32>
+  %sub.i = sub nsw <4 x i32> %conv, %conv1
+  %cmp.i = icmp sgt <4 x i16> %b, %a
+  %sub1.i = sub nsw <4 x i32> %conv1, %conv
+  %spec.select.i = select <4 x i1> %cmp.i, <4 x i32> %sub1.i, <4 x i32> %sub.i
+  %add = add nsw <4 x i32> %spec.select.i, splat (i32 19)
+  ret <4 x i32> %add
+}
+
+define <4 x i32> @abd_select_zext_add(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: abd_select_zext_add:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    cmhi v3.4h, v1.4h, v0.4h
+; CHECK-NEXT:    usubl v4.4s, v0.4h, v1.4h
+; CHECK-NEXT:    usubl v0.4s, v1.4h, v0.4h
+; CHECK-NEXT:    movi v2.4s, #19
+; CHECK-NEXT:    sshll v3.4s, v3.4h, #0
+; CHECK-NEXT:    bif v0.16b, v4.16b, v3.16b
+; CHECK-NEXT:    add v0.4s, v0.4s, v2.4s
+; CHECK-NEXT:    ret
+  %conv = zext <4 x i16> %a to <4 x i32>
+  %conv1 = zext <4 x i16> %b to <4 x i32>
+  %sub.i = sub nsw <4 x i32> %conv, %conv1
+  %cmp.i = icmp ugt <4 x i16> %b, %a
+  %sub1.i = sub nsw <4 x i32> %conv1, %conv
+  %spec.select.i = select <4 x i1> %cmp.i, <4 x i32> %sub1.i, <4 x i32> %sub.i
+  %add = add nsw <4 x i32> %spec.select.i, splat (i32 19)
+  ret <4 x i32> %add
+}
+
+define <4 x i32> @neg_abd_select_sext(<4 x i16> %a, <4 x i16> %b) {
+; CHECK-LABEL: neg_abd_select_sext:
+; CHECK:       // %bb.0: // %entry
+; CHECK-NEXT:    cmgt v2.4h, v1.4h, v0.4h
+; CHECK-NEXT:    ssubl v3.4s, v0.4h, v1.4h
+; CHECK-NEXT:    ssubl v0.4s, v1.4h, v0.4h
+; CHECK-NEXT:    sshll v2.4s, v2.4h, #0
+; CHECK-NEXT:    bit v0.16b, v3.16b, v2.16b
+; CHECK-NEXT:    ret
+entry:
+  %conv = sext <4 x i16> %a to <4 x i32>
+  %conv1 = sext <4 x i16> %b to <4 x i32>
+  %cmp = icmp slt <4 x i16> %a, %b
+  %sub = sub nsw <4 x i32> %conv, %conv1
+  %sub7 = sub nsw <4 x i32> %conv1, %conv
+  %cond = select <4 x i1> %cmp, <4 x i32> %sub, <4 x i32> %sub7
+  ret <4 x i32> %cond
+}
+
 declare <8 x i8> @llvm.aarch64.neon.umax.v8i8(<8 x i8>, <8 x i8>)
 declare <1 x i64> @llvm.aarch64.neon.saddlp.v1i64.v2i32(<2 x i32>)
 declare <8 x i8> @llvm.aarch64.neon.uabd.v8i8(<8 x i8>, <8 x i8>)

>From 2c0bcb5229afc2d03ca695cffcca0ca6fdf589c6 Mon Sep 17 00:00:00 2001
From: DaKnig <ZannyKnig at disroot.org>
Date: Thu, 9 Apr 2026 18:02:22 +0300
Subject: [PATCH 2/2] code

---
 llvm/include/llvm/CodeGen/SDPatternMatch.h    | 19 ++++---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 51 +++++++++++--------
 llvm/test/CodeGen/AArch64/abd-combine.ll      | 29 +++--------
 3 files changed, 50 insertions(+), 49 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/SDPatternMatch.h b/llvm/include/llvm/CodeGen/SDPatternMatch.h
index 899243691810c..9391ca945f82e 100644
--- a/llvm/include/llvm/CodeGen/SDPatternMatch.h
+++ b/llvm/include/llvm/CodeGen/SDPatternMatch.h
@@ -23,6 +23,7 @@
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/Support/KnownBits.h"
 
+#include <algorithm>
 #include <type_traits>
 
 namespace llvm {
@@ -1549,8 +1550,10 @@ inline auto m_IntrinsicWOChain(const OpndPreds &...Opnds) {
 
 struct SpecificNeg_match {
   SDValue V;
+  bool AllowTypeMismatch;
 
-  explicit SpecificNeg_match(SDValue V) : V(V) {}
+  explicit SpecificNeg_match(SDValue V, bool AllowTypeMismatch = false)
+      : V(V), AllowTypeMismatch(AllowTypeMismatch) {}
 
   template <typename MatchContext>
   bool match(const MatchContext &Ctx, SDValue N) {
@@ -1558,16 +1561,20 @@ struct SpecificNeg_match {
       return true;
 
     return ISD::matchBinaryPredicate(
-        V, N, [](ConstantSDNode *LHS, ConstantSDNode *RHS) {
-          return LHS->getAPIntValue() == -RHS->getAPIntValue();
-        });
+        V, N,
+        [](ConstantSDNode *LHS, ConstantSDNode *RHS) {
+          return APInt::isSameValue(LHS->getAPIntValue(), -RHS->getAPIntValue(),
+                                    /*SignedCompare=*/true);
+        },
+        /*AllowUndefs=*/false, AllowTypeMismatch);
   }
 };
 
 /// Match a negation of a specific value V, either as sub(0, V) or as
 /// constant(s) that are the negation of V's constant(s).
-inline SpecificNeg_match m_SpecificNeg(SDValue V) {
-  return SpecificNeg_match(V);
+inline SpecificNeg_match m_SpecificNeg(SDValue V,
+                                       bool AllowTypeMismatch = false) {
+  return SpecificNeg_match(V, AllowTypeMismatch);
 }
 
 template <typename... PatternTs> struct ReassociatableOpc_match {
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index aee5aabdc9e02..afdc4c14374be 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -12703,7 +12703,7 @@ SDValue DAGCombiner::foldSelectToABD(SDValue LHS, SDValue RHS, SDValue True,
                                      const SDLoc &DL) {
   bool IsSigned = isSignedIntSetCC(CC);
   unsigned ABDOpc = IsSigned ? ISD::ABDS : ISD::ABDU;
-  EVT VT = LHS.getValueType();
+  EVT VT = True.getValueType();
 
   if (LegalOperations && !hasOperation(ABDOpc, VT))
     return SDValue();
@@ -12727,38 +12727,47 @@ SDValue DAGCombiner::foldSelectToABD(SDValue LHS, SDValue RHS, SDValue True,
       TLI.isTypeLegal(VT) || TLI.getTypeAction(*DAG.getContext(), VT) ==
                                  TargetLowering::TypePromoteInteger;
 
+  auto LHSPat = ISD::isSignedIntSetCC(CC) ? m_SExtOrSelf(m_Specific(LHS))
+                                          : m_ZExtOrSelf(m_Specific(LHS));
+  auto RHSPat = ISD::isSignedIntSetCC(CC) ? m_SExtOrSelf(m_Specific(RHS))
+                                          : m_ZExtOrSelf(m_Specific(RHS));
+  auto GetAbdNode = [&] {
+    auto AbdNode = DAG.getNode(ABDOpc, DL, LHS.getValueType(), LHS, RHS);
+    return DAG.getZExtOrTrunc(AbdNode, DL, VT);
+  };
+
   switch (CC) {
   case ISD::SETGT:
   case ISD::SETGE:
   case ISD::SETUGT:
   case ISD::SETUGE:
-    if (sd_match(True, m_AnyOf(m_Sub(m_Specific(LHS), m_Specific(RHS)),
-                               m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))) &&
-        sd_match(False, m_AnyOf(m_Sub(m_Specific(RHS), m_Specific(LHS)),
-                                m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))))
-      return DAG.getNode(ABDOpc, DL, VT, LHS, RHS);
-    if (sd_match(True, m_AnyOf(m_Sub(m_Specific(RHS), m_Specific(LHS)),
-                               m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))) &&
-        sd_match(False, m_AnyOf(m_Sub(m_Specific(LHS), m_Specific(RHS)),
-                                m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))) &&
+    if (sd_match(True, m_AnyOf(m_Sub(LHSPat, RHSPat),
+                               m_Add(LHSPat, m_SpecificNeg(RHS, true)))) &&
+        sd_match(False, m_AnyOf(m_Sub(RHSPat, LHSPat),
+                                m_Add(RHSPat, m_SpecificNeg(LHS, true)))))
+      return GetAbdNode();
+    if (sd_match(True, m_AnyOf(m_Sub(RHSPat, LHSPat),
+                               m_Add(RHSPat, m_SpecificNeg(LHS, true)))) &&
+        sd_match(False, m_AnyOf(m_Sub(LHSPat, RHSPat),
+                                m_Add(LHSPat, m_SpecificNeg(RHS, true)))) &&
         IsTypeLegalOrPromote)
-      return DAG.getNegative(DAG.getNode(ABDOpc, DL, VT, LHS, RHS), DL, VT);
+      return DAG.getNegative(GetAbdNode(), DL, VT);
     break;
   case ISD::SETLT:
   case ISD::SETLE:
   case ISD::SETULT:
   case ISD::SETULE:
-    if (sd_match(True, m_AnyOf(m_Sub(m_Specific(RHS), m_Specific(LHS)),
-                               m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))) &&
-        sd_match(False, m_AnyOf(m_Sub(m_Specific(LHS), m_Specific(RHS)),
-                                m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))))
-      return DAG.getNode(ABDOpc, DL, VT, LHS, RHS);
-    if (sd_match(True, m_AnyOf(m_Sub(m_Specific(LHS), m_Specific(RHS)),
-                               m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))) &&
-        sd_match(False, m_AnyOf(m_Sub(m_Specific(RHS), m_Specific(LHS)),
-                                m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))) &&
+    if (sd_match(True, m_AnyOf(m_Sub(RHSPat, LHSPat),
+                               m_Add(RHSPat, m_SpecificNeg(LHS, true)))) &&
+        sd_match(False, m_AnyOf(m_Sub(LHSPat, RHSPat),
+                                m_Add(LHSPat, m_SpecificNeg(RHS, true)))))
+      return GetAbdNode();
+    if (sd_match(True, m_AnyOf(m_Sub(LHSPat, RHSPat),
+                               m_Add(LHSPat, m_SpecificNeg(RHS, true)))) &&
+        sd_match(False, m_AnyOf(m_Sub(RHSPat, LHSPat),
+                                m_Add(RHSPat, m_SpecificNeg(LHS, true)))) &&
         IsTypeLegalOrPromote)
-      return DAG.getNegative(DAG.getNode(ABDOpc, DL, VT, LHS, RHS), DL, VT);
+      return DAG.getNegative(GetAbdNode(), DL, VT);
     break;
   default:
     break;
diff --git a/llvm/test/CodeGen/AArch64/abd-combine.ll b/llvm/test/CodeGen/AArch64/abd-combine.ll
index 6d021ae0f48a9..f73b699daf096 100644
--- a/llvm/test/CodeGen/AArch64/abd-combine.ll
+++ b/llvm/test/CodeGen/AArch64/abd-combine.ll
@@ -526,11 +526,7 @@ define <1 x i64> @recursive() {
 define <4 x i32> @abd_select_sext(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: abd_select_sext:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    cmgt v2.4h, v1.4h, v0.4h
-; CHECK-NEXT:    ssubl v3.4s, v0.4h, v1.4h
-; CHECK-NEXT:    ssubl v0.4s, v1.4h, v0.4h
-; CHECK-NEXT:    sshll v2.4s, v2.4h, #0
-; CHECK-NEXT:    bif v0.16b, v3.16b, v2.16b
+; CHECK-NEXT:    sabdl v0.4s, v1.4h, v0.4h
 ; CHECK-NEXT:    ret
   %conv = sext <4 x i16> %a to <4 x i32>
   %conv1 = sext <4 x i16> %b to <4 x i32>
@@ -544,13 +540,9 @@ define <4 x i32> @abd_select_sext(<4 x i16> %a, <4 x i16> %b) {
 define <4 x i32> @abd_select_sext_add(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: abd_select_sext_add:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    cmgt v3.4h, v1.4h, v0.4h
-; CHECK-NEXT:    ssubl v4.4s, v0.4h, v1.4h
-; CHECK-NEXT:    ssubl v0.4s, v1.4h, v0.4h
 ; CHECK-NEXT:    movi v2.4s, #19
-; CHECK-NEXT:    sshll v3.4s, v3.4h, #0
-; CHECK-NEXT:    bif v0.16b, v4.16b, v3.16b
-; CHECK-NEXT:    add v0.4s, v0.4s, v2.4s
+; CHECK-NEXT:    sabal v2.4s, v1.4h, v0.4h
+; CHECK-NEXT:    mov v0.16b, v2.16b
 ; CHECK-NEXT:    ret
   %conv = sext <4 x i16> %a to <4 x i32>
   %conv1 = sext <4 x i16> %b to <4 x i32>
@@ -565,13 +557,9 @@ define <4 x i32> @abd_select_sext_add(<4 x i16> %a, <4 x i16> %b) {
 define <4 x i32> @abd_select_zext_add(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: abd_select_zext_add:
 ; CHECK:       // %bb.0:
-; CHECK-NEXT:    cmhi v3.4h, v1.4h, v0.4h
-; CHECK-NEXT:    usubl v4.4s, v0.4h, v1.4h
-; CHECK-NEXT:    usubl v0.4s, v1.4h, v0.4h
 ; CHECK-NEXT:    movi v2.4s, #19
-; CHECK-NEXT:    sshll v3.4s, v3.4h, #0
-; CHECK-NEXT:    bif v0.16b, v4.16b, v3.16b
-; CHECK-NEXT:    add v0.4s, v0.4s, v2.4s
+; CHECK-NEXT:    uabal v2.4s, v1.4h, v0.4h
+; CHECK-NEXT:    mov v0.16b, v2.16b
 ; CHECK-NEXT:    ret
   %conv = zext <4 x i16> %a to <4 x i32>
   %conv1 = zext <4 x i16> %b to <4 x i32>
@@ -586,11 +574,8 @@ define <4 x i32> @abd_select_zext_add(<4 x i16> %a, <4 x i16> %b) {
 define <4 x i32> @neg_abd_select_sext(<4 x i16> %a, <4 x i16> %b) {
 ; CHECK-LABEL: neg_abd_select_sext:
 ; CHECK:       // %bb.0: // %entry
-; CHECK-NEXT:    cmgt v2.4h, v1.4h, v0.4h
-; CHECK-NEXT:    ssubl v3.4s, v0.4h, v1.4h
-; CHECK-NEXT:    ssubl v0.4s, v1.4h, v0.4h
-; CHECK-NEXT:    sshll v2.4s, v2.4h, #0
-; CHECK-NEXT:    bit v0.16b, v3.16b, v2.16b
+; CHECK-NEXT:    sabdl v0.4s, v0.4h, v1.4h
+; CHECK-NEXT:    neg v0.4s, v0.4s
 ; CHECK-NEXT:    ret
 entry:
   %conv = sext <4 x i16> %a to <4 x i32>



More information about the llvm-commits mailing list