[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