[llvm-branch-commits] [llvm] release/23.x: [SelectionDAG] Don't always use abs(sub) when expanding abdu (#235043) (PR #235256)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Oct 24 01:03:07 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-aarch64

Author: llvmbot

<details>
<summary>Changes</summary>

Backport f16dbe0ec4b653736148c78bebdefcfe1c88198e

Requested by: @<!-- -->nikic

---
Full diff: https://github.com/llvm/llvm-project/pull/235256.diff


6 Files Affected:

- (modified) llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp (+11-7) 
- (modified) llvm/test/CodeGen/AArch64/abdu.ll (+16) 
- (modified) llvm/test/CodeGen/AArch64/neon-abd.ll (+57) 
- (added) llvm/test/CodeGen/ARM/abdu.ll (+25) 
- (modified) llvm/test/CodeGen/X86/abdu-vector-128.ll (+102) 
- (modified) llvm/test/CodeGen/X86/abdu.ll (+36) 


``````````diff
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 8e3d51509e4751..6e7349f1a44253 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -11377,16 +11377,20 @@ SDValue TargetLowering::expandABD(SDNode *N, SelectionDAG &DAG) const {
                        DAG.getNode(ISD::USUBSAT, dl, VT, RHS, LHS));
   }
 
-  // If the subtract doesn't overflow then just use abs(sub())
+  // abds, or abdu with non-negative operands: if the sub is nsw, abs(sub).
+  // Otherwise abdu: if the sub is nuw then lhs >= rhs, so just sub.
   bool IsNonNegative = DAG.SignBitIsZero(LHS) && DAG.SignBitIsZero(RHS);
+  bool UseSigned = IsSigned || IsNonNegative;
 
-  if (DAG.willNotOverflowSub(IsSigned || IsNonNegative, LHS, RHS))
-    return DAG.getNode(ISD::ABS, dl, VT,
-                       DAG.getNode(ISD::SUB, dl, VT, LHS, RHS));
+  if (DAG.willNotOverflowSub(UseSigned, LHS, RHS)) {
+    SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, LHS, RHS);
+    return UseSigned ? DAG.getNode(ISD::ABS, dl, VT, Sub) : Sub;
+  }
 
-  if (DAG.willNotOverflowSub(IsSigned || IsNonNegative, RHS, LHS))
-    return DAG.getNode(ISD::ABS, dl, VT,
-                       DAG.getNode(ISD::SUB, dl, VT, RHS, LHS));
+  if (DAG.willNotOverflowSub(UseSigned, RHS, LHS)) {
+    SDValue Sub = DAG.getNode(ISD::SUB, dl, VT, RHS, LHS);
+    return UseSigned ? DAG.getNode(ISD::ABS, dl, VT, Sub) : Sub;
+  }
 
   EVT CCVT = getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
   ISD::CondCode CC = IsSigned ? ISD::CondCode::SETGT : ISD::CondCode::SETUGT;
diff --git a/llvm/test/CodeGen/AArch64/abdu.ll b/llvm/test/CodeGen/AArch64/abdu.ll
index 3cbe648788a848..e7ca229391019f 100644
--- a/llvm/test/CodeGen/AArch64/abdu.ll
+++ b/llvm/test/CodeGen/AArch64/abdu.ll
@@ -442,6 +442,22 @@ define i128 @abd_select_i128(i128 %a, i128 %b) nounwind {
   ret i128 %sub
 }
 
+; l < 2^63 <= r, so abdu(l, r) == r - l: should not become abs(sub).
+define i64 @abd_select_known_order_i64(i64 %a, i64 %b) nounwind {
+; CHECK-LABEL: abd_select_known_order_i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    orr x8, x1, #0x8000000000000000
+; CHECK-NEXT:    sub x0, x8, x0, lsr #1
+; CHECK-NEXT:    ret
+  %l = lshr i64 %a, 1
+  %r = or i64 %b, -9223372036854775808
+  %c = icmp ugt i64 %l, %r
+  %s1 = sub i64 %l, %r
+  %s2 = sub i64 %r, %l
+  %res = select i1 %c, i64 %s1, i64 %s2
+  ret i64 %res
+}
+
 declare i8 @llvm.abs.i8(i8, i1)
 declare i16 @llvm.abs.i16(i16, i1)
 declare i32 @llvm.abs.i32(i32, i1)
diff --git a/llvm/test/CodeGen/AArch64/neon-abd.ll b/llvm/test/CodeGen/AArch64/neon-abd.ll
index e6c931c6d1834f..4b7efcfdca3db3 100644
--- a/llvm/test/CodeGen/AArch64/neon-abd.ll
+++ b/llvm/test/CodeGen/AArch64/neon-abd.ll
@@ -787,6 +787,63 @@ define <4 x i16> @abs_diff_add_v4i16_rii(<4 x i16> %a) {
   ret <4 x i16> %conv1
 }
 
+; l < 2^63 <= r, so abdu(l, r) == r - l: should not become abs(sub).
+define <2 x i64> @uabd_known_order_v2i64(<2 x i64> %a, <2 x i64> %b) {
+; CHECK-LABEL: uabd_known_order_v2i64:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    movi v2.2d, #0000000000000000
+; CHECK-NEXT:    ushr v0.2d, v0.2d, #1
+; CHECK-NEXT:    fneg v2.2d, v2.2d
+; CHECK-NEXT:    orr v1.16b, v1.16b, v2.16b
+; CHECK-NEXT:    sub v0.2d, v1.2d, v0.2d
+; CHECK-NEXT:    ret
+  %l = lshr <2 x i64> %a, splat (i64 1)
+  %r = or <2 x i64> %b, splat (i64 -9223372036854775808)
+  %c = icmp ugt <2 x i64> %l, %r
+  %s1 = sub <2 x i64> %l, %r
+  %s2 = sub <2 x i64> %r, %l
+  %res = select <2 x i1> %c, <2 x i64> %s1, <2 x i64> %s2
+  ret <2 x i64> %res
+}
+
+; l < 2^31 <= r, so abdu(l, r) == r - l (uabd is legal, so it isn't expanded).
+define <4 x i32> @uabd_known_order_v4i32(<4 x i32> %a, <4 x i32> %b) {
+; CHECK-LABEL: uabd_known_order_v4i32:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    ushr v0.4s, v0.4s, #1
+; CHECK-NEXT:    orr v1.4s, #128, lsl #24
+; CHECK-NEXT:    uabd v0.4s, v0.4s, v1.4s
+; CHECK-NEXT:    ret
+  %l = lshr <4 x i32> %a, splat (i32 1)
+  %r = or <4 x i32> %b, splat (i32 -2147483648)
+  %c = icmp ugt <4 x i32> %l, %r
+  %s1 = sub <4 x i32> %l, %r
+  %s2 = sub <4 x i32> %r, %l
+  %res = select <4 x i1> %c, <4 x i32> %s1, <4 x i32> %s2
+  ret <4 x i32> %res
+}
+
+; pr233087: the low half becomes abdu(b, -1) == ~b: should not become abs(sub).
+define <4 x i64> @uabd_v4i64_pr233087(<4 x i64> %a, <4 x i64> %b) {
+; CHECK-LABEL: uabd_v4i64_pr233087:
+; CHECK:       // %bb.0:
+; CHECK-NEXT:    adrp x8, .LCPI56_0
+; CHECK-NEXT:    ldr q0, [x8, :lo12:.LCPI56_0]
+; CHECK-NEXT:    cmge v0.2d, v1.2d, v0.2d
+; CHECK-NEXT:    uqsub v1.2d, v0.2d, v3.2d
+; CHECK-NEXT:    uqsub v0.2d, v3.2d, v0.2d
+; CHECK-NEXT:    orr v1.16b, v0.16b, v1.16b
+; CHECK-NEXT:    mvn v0.16b, v2.16b
+; CHECK-NEXT:    ret
+  %cmp = icmp sge <4 x i64> %a, <i64 -9223372036854775808, i64 -9223372036854775808, i64 1, i64 -9223372036854775808>
+  %y = sext <4 x i1> %cmp to <4 x i64>
+  %c = icmp ugt <4 x i64> %b, %y
+  %s1 = sub <4 x i64> %b, %y
+  %s2 = sub <4 x i64> %y, %b
+  %r = select <4 x i1> %c, <4 x i64> %s1, <4 x i64> %s2
+  ret <4 x i64> %r
+}
+
 declare <8 x i8> @llvm.abs.v8i8(<8 x i8>, i1)
 declare <16 x i8> @llvm.abs.v16i8(<16 x i8>, i1)
 
diff --git a/llvm/test/CodeGen/ARM/abdu.ll b/llvm/test/CodeGen/ARM/abdu.ll
new file mode 100644
index 00000000000000..7526f8c7045e17
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/abdu.ll
@@ -0,0 +1,25 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=armv7a-eabihf | FileCheck %s --check-prefixes=ARM
+; RUN: llc < %s -mtriple=thumbv7m-eabi | FileCheck %s --check-prefixes=THUMB
+
+; l < 2^31 <= r, so abdu(l, r) == r - l: should not become abs(sub).
+define i32 @abd_select_known_order_i32(i32 %a, i32 %b) nounwind {
+; ARM-LABEL: abd_select_known_order_i32:
+; ARM:       @ %bb.0:
+; ARM-NEXT:    orr r1, r1, #-2147483648
+; ARM-NEXT:    sub r0, r1, r0, lsr #1
+; ARM-NEXT:    bx lr
+;
+; THUMB-LABEL: abd_select_known_order_i32:
+; THUMB:       @ %bb.0:
+; THUMB-NEXT:    orr r1, r1, #-2147483648
+; THUMB-NEXT:    sub.w r0, r1, r0, lsr #1
+; THUMB-NEXT:    bx lr
+  %l = lshr i32 %a, 1
+  %r = or i32 %b, -2147483648
+  %c = icmp ugt i32 %l, %r
+  %s1 = sub i32 %l, %r
+  %s2 = sub i32 %r, %l
+  %res = select i1 %c, i32 %s1, i32 %s2
+  ret i32 %res
+}
diff --git a/llvm/test/CodeGen/X86/abdu-vector-128.ll b/llvm/test/CodeGen/X86/abdu-vector-128.ll
index 78b315a3773ec0..0eaf18065ba381 100644
--- a/llvm/test/CodeGen/X86/abdu-vector-128.ll
+++ b/llvm/test/CodeGen/X86/abdu-vector-128.ll
@@ -771,6 +771,108 @@ define <8 x i16> @abd_cmp_v8i16_multiuse_sub(<8 x i16> %a, <8 x i16> %b) nounwin
   ret <8 x i16> %res
 }
 
+; pr233087: the low half becomes abdu(b, -1) == ~b: should not become abs(sub).
+define <4 x i64> @abd_select_v4i64_pr233087(<4 x i64> %a, <4 x i64> %b) nounwind {
+; SSE2-LABEL: abd_select_v4i64_pr233087:
+; SSE2:       # %bb.0:
+; SSE2-NEXT:    pxor {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT:    movdqa {{.*#+}} xmm0 = [2147483649,9223372039002259456]
+; SSE2-NEXT:    pcmpgtd %xmm1, %xmm0
+; SSE2-NEXT:    pshufd {{.*#+}} xmm4 = xmm0[0,0,2,2]
+; SSE2-NEXT:    pshufd {{.*#+}} xmm1 = xmm1[1,1,3,3]
+; SSE2-NEXT:    pcmpeqd {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
+; SSE2-NEXT:    pand %xmm4, %xmm1
+; SSE2-NEXT:    pshufd {{.*#+}} xmm4 = xmm0[1,1,3,3]
+; SSE2-NEXT:    por %xmm1, %xmm4
+; SSE2-NEXT:    pcmpeqd %xmm0, %xmm0
+; SSE2-NEXT:    pxor %xmm0, %xmm4
+; SSE2-NEXT:    movdqa {{.*#+}} xmm1 = [9223372039002259456,9223372039002259456]
+; SSE2-NEXT:    movdqa %xmm4, %xmm5
+; SSE2-NEXT:    pxor %xmm1, %xmm5
+; SSE2-NEXT:    pxor %xmm3, %xmm1
+; SSE2-NEXT:    movdqa %xmm1, %xmm6
+; SSE2-NEXT:    pcmpgtd %xmm5, %xmm6
+; SSE2-NEXT:    pshufd {{.*#+}} xmm7 = xmm6[0,0,2,2]
+; SSE2-NEXT:    pcmpeqd %xmm5, %xmm1
+; SSE2-NEXT:    pshufd {{.*#+}} xmm5 = xmm1[1,1,3,3]
+; SSE2-NEXT:    pand %xmm7, %xmm5
+; SSE2-NEXT:    pshufd {{.*#+}} xmm1 = xmm6[1,1,3,3]
+; SSE2-NEXT:    por %xmm5, %xmm1
+; SSE2-NEXT:    psubq %xmm4, %xmm3
+; SSE2-NEXT:    pxor %xmm1, %xmm3
+; SSE2-NEXT:    psubq %xmm3, %xmm1
+; SSE2-NEXT:    pxor %xmm2, %xmm0
+; SSE2-NEXT:    retq
+;
+; SSE42-LABEL: abd_select_v4i64_pr233087:
+; SSE42:       # %bb.0:
+; SSE42-NEXT:    movdqa {{.*#+}} xmm4 = [1,9223372036854775808]
+; SSE42-NEXT:    pcmpgtq %xmm1, %xmm4
+; SSE42-NEXT:    pcmpeqd %xmm0, %xmm0
+; SSE42-NEXT:    movdqa %xmm4, %xmm5
+; SSE42-NEXT:    pxor %xmm0, %xmm5
+; SSE42-NEXT:    pxor {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm4
+; SSE42-NEXT:    movdqa {{.*#+}} xmm1 = [9223372036854775808,9223372036854775808]
+; SSE42-NEXT:    pxor %xmm3, %xmm1
+; SSE42-NEXT:    pcmpgtq %xmm4, %xmm1
+; SSE42-NEXT:    psubq %xmm5, %xmm3
+; SSE42-NEXT:    pxor %xmm1, %xmm3
+; SSE42-NEXT:    psubq %xmm3, %xmm1
+; SSE42-NEXT:    pxor %xmm2, %xmm0
+; SSE42-NEXT:    retq
+;
+; AVX1-LABEL: abd_select_v4i64_pr233087:
+; AVX1:       # %bb.0:
+; AVX1-NEXT:    vextractf128 $1, %ymm0, %xmm0
+; AVX1-NEXT:    vmovdqa {{.*#+}} xmm2 = [1,9223372036854775808]
+; AVX1-NEXT:    vpcmpgtq %xmm0, %xmm2, %xmm0
+; AVX1-NEXT:    vpcmpeqd %xmm2, %xmm2, %xmm2
+; AVX1-NEXT:    vpxor %xmm2, %xmm0, %xmm3
+; AVX1-NEXT:    vpxor {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0
+; AVX1-NEXT:    vextractf128 $1, %ymm1, %xmm4
+; AVX1-NEXT:    vpxor {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm4, %xmm5
+; AVX1-NEXT:    vpcmpgtq %xmm0, %xmm5, %xmm0
+; AVX1-NEXT:    vpsubq %xmm3, %xmm4, %xmm3
+; AVX1-NEXT:    vpxor %xmm0, %xmm3, %xmm3
+; AVX1-NEXT:    vpsubq %xmm3, %xmm0, %xmm0
+; AVX1-NEXT:    vpxor %xmm2, %xmm1, %xmm1
+; AVX1-NEXT:    vinsertf128 $1, %xmm0, %ymm1, %ymm0
+; AVX1-NEXT:    retq
+;
+; AVX2-LABEL: abd_select_v4i64_pr233087:
+; AVX2:       # %bb.0:
+; AVX2-NEXT:    vmovdqa {{.*#+}} ymm2 = [9223372036854775808,9223372036854775808,1,9223372036854775808]
+; AVX2-NEXT:    vpcmpgtq %ymm0, %ymm2, %ymm0
+; AVX2-NEXT:    vpcmpeqd %ymm2, %ymm2, %ymm2
+; AVX2-NEXT:    vpxor %ymm2, %ymm0, %ymm2
+; AVX2-NEXT:    vpbroadcastq {{.*#+}} ymm3 = [9223372036854775808,9223372036854775808,9223372036854775808,9223372036854775808]
+; AVX2-NEXT:    vpxor %ymm3, %ymm1, %ymm3
+; AVX2-NEXT:    vpbroadcastq {{.*#+}} ymm4 = [9223372036854775807,9223372036854775807,9223372036854775807,9223372036854775807]
+; AVX2-NEXT:    vpxor %ymm4, %ymm0, %ymm0
+; AVX2-NEXT:    vpcmpgtq %ymm0, %ymm3, %ymm0
+; AVX2-NEXT:    vpsubq %ymm2, %ymm1, %ymm1
+; AVX2-NEXT:    vpxor %ymm0, %ymm1, %ymm1
+; AVX2-NEXT:    vpsubq %ymm1, %ymm0, %ymm0
+; AVX2-NEXT:    retq
+;
+; AVX512-LABEL: abd_select_v4i64_pr233087:
+; AVX512:       # %bb.0:
+; AVX512-NEXT:    vmovdqa {{.*#+}} ymm2 = [9223372036854775808,9223372036854775808,1,9223372036854775808]
+; AVX512-NEXT:    vpcmpgtq %ymm0, %ymm2, %ymm0
+; AVX512-NEXT:    vpternlogq {{.*#+}} ymm0 = ~ymm0
+; AVX512-NEXT:    vpminuq %ymm0, %ymm1, %ymm2
+; AVX512-NEXT:    vpmaxuq %ymm0, %ymm1, %ymm0
+; AVX512-NEXT:    vpsubq %ymm2, %ymm0, %ymm0
+; AVX512-NEXT:    retq
+  %cmp = icmp sge <4 x i64> %a, <i64 -9223372036854775808, i64 -9223372036854775808, i64 1, i64 -9223372036854775808>
+  %y = sext <4 x i1> %cmp to <4 x i64>
+  %c = icmp ugt <4 x i64> %b, %y
+  %s1 = sub <4 x i64> %b, %y
+  %s2 = sub <4 x i64> %y, %b
+  %r = select <4 x i1> %c, <4 x i64> %s1, <4 x i64> %s2
+  ret <4 x i64> %r
+}
+
 declare <16 x i8> @llvm.abs.v16i8(<16 x i8>, i1)
 declare <8 x i16> @llvm.abs.v8i16(<8 x i16>, i1)
 declare <4 x i32> @llvm.abs.v4i32(<4 x i32>, i1)
diff --git a/llvm/test/CodeGen/X86/abdu.ll b/llvm/test/CodeGen/X86/abdu.ll
index 520a6917aff53a..78d359defac036 100644
--- a/llvm/test/CodeGen/X86/abdu.ll
+++ b/llvm/test/CodeGen/X86/abdu.ll
@@ -979,6 +979,42 @@ entry:
   ret i32 %a
 }
 
+; l < 2^63 <= r, so abdu(l, r) == r - l: should not become abs(sub).
+define i64 @abd_select_known_order_i64(i64 %a, i64 %b) nounwind {
+; X86-LABEL: abd_select_known_order_i64:
+; X86:       # %bb.0:
+; X86-NEXT:    pushl %esi
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
+; X86-NEXT:    shrdl $1, %esi, %ecx
+; X86-NEXT:    shrl %esi
+; X86-NEXT:    movl $-2147483648, %edx # imm = 0x80000000
+; X86-NEXT:    orl {{[0-9]+}}(%esp), %edx
+; X86-NEXT:    subl %ecx, %eax
+; X86-NEXT:    sbbl %esi, %edx
+; X86-NEXT:    popl %esi
+; X86-NEXT:    retl
+;
+; X64-LABEL: abd_select_known_order_i64:
+; X64:       # %bb.0:
+; X64-NEXT:    shrq %rdi
+; X64-NEXT:    movabsq $-9223372036854775808, %rcx # imm = 0x8000000000000000
+; X64-NEXT:    orq %rsi, %rcx
+; X64-NEXT:    movq %rcx, %rax
+; X64-NEXT:    subq %rdi, %rax
+; X64-NEXT:    subq %rcx, %rdi
+; X64-NEXT:    cmovaeq %rdi, %rax
+; X64-NEXT:    retq
+  %l = lshr i64 %a, 1
+  %r = or i64 %b, -9223372036854775808
+  %c = icmp ugt i64 %l, %r
+  %s1 = sub i64 %l, %r
+  %s2 = sub i64 %r, %l
+  %res = select i1 %c, i64 %s1, i64 %s2
+  ret i64 %res
+}
+
 declare i8 @llvm.abs.i8(i8, i1)
 declare i16 @llvm.abs.i16(i16, i1)
 declare i32 @llvm.abs.i32(i32, i1)

``````````

</details>


https://github.com/llvm/llvm-project/pull/235256


More information about the llvm-branch-commits mailing list