[llvm] [SDAG] Allow S/Zext in select-abd pattern (PR #191207)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 18 12:39:20 PDT 2026
https://github.com/DaKnig updated https://github.com/llvm/llvm-project/pull/191207
>From 4acfb6ad305c09230ef15c4f668ddd457ac3e45f Mon Sep 17 00:00:00 2001
From: DaKnig <ZannyKnig at disroot.org>
Date: Thu, 9 Apr 2026 17:39:02 +0300
Subject: [PATCH 1/4] [SDAG] Allow S/Zext in select-abd pattern
(select (setcc a, b, s??), (sub (*sext* a), (*sext* b)),
(sub (*sext* b), (*sext* a)))
Into: (zext (abds a, b))
>From 083bd8df47a105b3623cc8a38b589ce7840635fa Mon Sep 17 00:00:00 2001
From: DaKnig <ZannyKnig at disroot.org>
Date: Thu, 9 Apr 2026 17:39:28 +0300
Subject: [PATCH 2/4] 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 7f061df54300597707173678353b97d63a5e89a2 Mon Sep 17 00:00:00 2001
From: DaKnig <ZannyKnig at disroot.org>
Date: Thu, 9 Apr 2026 18:02:22 +0300
Subject: [PATCH 3/4] 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 06c6cc183abcb..9e82f38cc908c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -12708,7 +12708,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();
@@ -12732,38 +12732,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>
>From 675310d378de8e7ebdbbe72a52ae48897240c208 Mon Sep 17 00:00:00 2001
From: DaKnig <ZannyKnig at disroot.org>
Date: Sat, 18 Apr 2026 22:37:48 +0300
Subject: [PATCH 4/4] restore const handling
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 9e82f38cc908c..6f674fa0297be 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -12747,14 +12747,14 @@ SDValue DAGCombiner::foldSelectToABD(SDValue LHS, SDValue RHS, SDValue True,
case ISD::SETUGT:
case ISD::SETUGE:
if (sd_match(True, m_AnyOf(m_Sub(LHSPat, RHSPat),
- m_Add(LHSPat, m_SpecificNeg(RHS, true)))) &&
+ m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))) &&
sd_match(False, m_AnyOf(m_Sub(RHSPat, LHSPat),
- m_Add(RHSPat, m_SpecificNeg(LHS, true)))))
+ m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))))
return GetAbdNode();
if (sd_match(True, m_AnyOf(m_Sub(RHSPat, LHSPat),
- m_Add(RHSPat, m_SpecificNeg(LHS, true)))) &&
+ m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))) &&
sd_match(False, m_AnyOf(m_Sub(LHSPat, RHSPat),
- m_Add(LHSPat, m_SpecificNeg(RHS, true)))) &&
+ m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))) &&
IsTypeLegalOrPromote)
return DAG.getNegative(GetAbdNode(), DL, VT);
break;
@@ -12763,14 +12763,14 @@ SDValue DAGCombiner::foldSelectToABD(SDValue LHS, SDValue RHS, SDValue True,
case ISD::SETULT:
case ISD::SETULE:
if (sd_match(True, m_AnyOf(m_Sub(RHSPat, LHSPat),
- m_Add(RHSPat, m_SpecificNeg(LHS, true)))) &&
+ m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))) &&
sd_match(False, m_AnyOf(m_Sub(LHSPat, RHSPat),
- m_Add(LHSPat, m_SpecificNeg(RHS, true)))))
+ m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))))
return GetAbdNode();
if (sd_match(True, m_AnyOf(m_Sub(LHSPat, RHSPat),
- m_Add(LHSPat, m_SpecificNeg(RHS, true)))) &&
+ m_Add(m_Specific(LHS), m_SpecificNeg(RHS)))) &&
sd_match(False, m_AnyOf(m_Sub(RHSPat, LHSPat),
- m_Add(RHSPat, m_SpecificNeg(LHS, true)))) &&
+ m_Add(m_Specific(RHS), m_SpecificNeg(LHS)))) &&
IsTypeLegalOrPromote)
return DAG.getNegative(GetAbdNode(), DL, VT);
break;
More information about the llvm-commits
mailing list