Skip to content

[SDAG] Fix invalid sign bit condition for abs(sub) -> abdu fold - #215548

Merged
Benjins merged 1 commit into
llvm:mainfrom
Benjins:bns-fix-abs-sub-abdu-fold
Aug 18, 2026
Merged

[SDAG] Fix invalid sign bit condition for abs(sub) -> abdu fold#215548
Benjins merged 1 commit into
llvm:mainfrom
Benjins:bns-fix-abs-sub-abdu-fold

Conversation

@Benjins

@Benjins Benjins commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

The fold here for (abs (sub x y)) -> (abdu x y) was proven in Alive, assuming that both operands had a sign bit of zero. However, the code was checking if x had a sign bit of zero and y had a sign bit of 1

Fixes #214942

Original Alive proof from #186659 : https://alive2.llvm.org/ce/z/HfPF5q
A variant that's explicitly (abs (sub x y)): https://alive2.llvm.org/ce/z/QEgDaa
And changing the range to 32770 or higher there will break the transformation

See also previously: #196782 which seemed to fix a variant of this in the abs(add) path

Also, I assume this will want to be cherry-picked for the 23.x release branch since it's a regression from 22.x

cc @DaKnig

The fold here for (abs (sub x y)) -> (abdu x y) was proven in Alive, assuming
that both operands had a sign bit of zero. However, the code was checking if
x had a sign bit of zero and y had a sign bit of 1

Fixes llvm#214942
@Benjins
Benjins requested a review from RKSimon August 11, 2026 13:06
@llvmorg-github-actions

llvmorg-github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-llvm-selectiondag

Author: Benji Smith (Benjins)

Changes

The fold here for (abs (sub x y)) -> (abdu x y) was proven in Alive, assuming that both operands had a sign bit of zero. However, the code was checking if x had a sign bit of zero and y had a sign bit of 1

Fixes #214942

Original Alive proof from #186659 : https://alive2.llvm.org/ce/z/HfPF5q
A variant that's explicitly (abs (sub x y)): https://alive2.llvm.org/ce/z/QEgDaa
And changing the range to 32770 or higher there will break the transformation

See also previously: #196782 which seemed to fix a variant of this in the abs(add) path

Also, I assume this will want to be cherry-picked for the 23.x release branch since it's a regression from 22.x

cc @DaKnig


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

2 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+2-2)
  • (modified) llvm/test/CodeGen/X86/abdu.ll (+30)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 1095464a1ebdd..70645a5bf1714 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -12237,8 +12237,8 @@ SDValue DAGCombiner::foldABSToABD(SDNode *N, const SDLoc &DL) {
       return CreateZextedAbd(ISD::ABDS);
 
     // fold (abs (sub x, y)) -> abdu(x, y)
-    bool Op1SignBitIsOne = DAG.computeKnownBits(Op1).isNegative();
-    bool AbsOpWillNUW = !IsAdd && DAG.SignBitIsZero(Op0) && Op1SignBitIsOne;
+    bool AbsOpWillNUW =
+        !IsAdd && DAG.SignBitIsZero(Op0) && DAG.SignBitIsZero(Op1);
 
     if (hasOperation(ISD::ABDU, VT) && AbsOpWillNUW)
       return CreateZextedAbd(ISD::ABDU);
diff --git a/llvm/test/CodeGen/X86/abdu.ll b/llvm/test/CodeGen/X86/abdu.ll
index b8bc3649773f2..520a6917aff53 100644
--- a/llvm/test/CodeGen/X86/abdu.ll
+++ b/llvm/test/CodeGen/X86/abdu.ll
@@ -949,6 +949,36 @@ define i128 @abd_select_i128(i128 %a, i128 %b) nounwind {
   ret i128 %sub
 }
 
+define i32 @abs_sub_abdu_sign_check(i32 %p0) {
+; X86-LABEL: abs_sub_abdu_sign_check:
+; X86:       # %bb.0: # %entry
+; X86-NEXT:    cmpl $0, {{[0-9]+}}(%esp)
+; X86-NEXT:    movl $1000000000, %eax # imm = 0x3B9ACA00
+; X86-NEXT:    movl $-2039640824, %ecx # imm = 0x866D8D08
+; X86-NEXT:    cmovel %eax, %ecx
+; X86-NEXT:    movl %ecx, %eax
+; X86-NEXT:    negl %eax
+; X86-NEXT:    cmovsl %ecx, %eax
+; X86-NEXT:    retl
+;
+; X64-LABEL: abs_sub_abdu_sign_check:
+; X64:       # %bb.0: # %entry
+; X64-NEXT:    testl %edi, %edi
+; X64-NEXT:    movl $1000000000, %eax # imm = 0x3B9ACA00
+; X64-NEXT:    movl $-2039640824, %ecx # imm = 0x866D8D08
+; X64-NEXT:    cmovel %eax, %ecx
+; X64-NEXT:    movl %ecx, %eax
+; X64-NEXT:    negl %eax
+; X64-NEXT:    cmovsl %ecx, %eax
+; X64-NEXT:    retq
+entry:
+  %cmp = icmp eq i32 %p0, 0
+  %v = select i1 %cmp, i32 0, i32 1255326472
+  %s = sub i32 %v, -1000000000
+  %a = call i32 @llvm.abs.i32(i32 %s, i1 false)
+  ret i32 %a
+}
+
 declare i8 @llvm.abs.i8(i8, i1)
 declare i16 @llvm.abs.i16(i16, i1)
 declare i32 @llvm.abs.i32(i32, i1)

@topperc

topperc commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

When #186659 added fold (abs (add x, -y)) -> abdu(x, y) did it get this conditional operator reversed?

    bool Op1SignBitIsOne = DAG.computeKnownBits(Op1).isNegative();
    bool AbsOpWillNUW = DAG.SignBitIsZero(Op0) &&
                        (IsAdd ? DAG.SignBitIsZero(Op1) : Op1SignBitIsOne);

Prior to that there was a DAG.SignBitIsZero(Op1), but after it looks like the Op1SignBitIsOne is applied to sub?

@DaKnig

DaKnig commented Aug 14, 2026 via email

Copy link
Copy Markdown
Contributor

@DaKnig

DaKnig commented Aug 14, 2026 via email

Copy link
Copy Markdown
Contributor

@topperc topperc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@DaKnig

DaKnig commented Aug 15, 2026 via email

Copy link
Copy Markdown
Contributor

@Benjins

Benjins commented Aug 15, 2026

Copy link
Copy Markdown
Contributor Author

The patch, as is, is incorrect for the case of IsAdd.

I'm a bit confused: at the moment, the patch doesn't affect what happens when IsAdd is true: either it's handled earlier in the function or it falls through to the return SDValue();. Do you mean we should also patch the code earlier in the function that deals with folding adds in the NSW case?

@topperc

topperc commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

The patch, as is, is incorrent for the case of IsAdd. Please change the code as described by @topperc : bool Op1SignBitIsOne = DAG.computeKnownBits(Op1).isNegative(); bool AbsOpInSignedRange = DAG.SignBitIsZero(Op0) && (IsAdd ? Op1SignBitIsOne: DAG.SignBitIsZero(Op1)); The condition should be inverted.

On August 14, 2026 5:57:48 PM GMT+02:00, Craig Topper @.> wrote: @topperc approved this pull request. LGTM -- Reply to this email directly or view it on GitHub: #215548 (review) You are receiving this because you were mentioned. Message ID: @.>

My comments were just trying to understand the history. The IsAdd code was removed in a later commit but left the subtract broken due to the inverted conditional that existed when add was removed.

@Benjins
Benjins enabled auto-merge (squash) August 18, 2026 01:53
@Benjins
Benjins merged commit 93030c3 into llvm:main Aug 18, 2026
15 checks passed
@Benjins
Benjins deleted the bns-fix-abs-sub-abdu-fold branch August 18, 2026 01:54
@Benjins

Benjins commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

/cherry-pick 93030c3

@llvmbot

llvmbot commented Aug 18, 2026

Copy link
Copy Markdown
Member

/cherry-pick 93030c3

Error: Command failed due to missing milestone.

@Benjins Benjins added this to the LLVM 23.x Release milestone Aug 19, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in LLVM Release Status Aug 19, 2026
@github-project-automation github-project-automation Bot moved this from Needs Triage to Done in LLVM Release Status Aug 19, 2026
@Benjins

Benjins commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

/cherry-pick 93030c3

@llvmbot

llvmbot commented Aug 19, 2026

Copy link
Copy Markdown
Member

/pull-request #217203

dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Aug 20, 2026
…#215548)

The fold here for (abs (sub x y)) -> (abdu x y) was proven in Alive,
assuming that both operands had a sign bit of zero. However, the code
was checking if x had a sign bit of zero and y had a sign bit of 1

Fixes llvm#214942

Original Alive proof from
llvm#186659 :
https://alive2.llvm.org/ce/z/HfPF5q
A variant that's explicitly (abs (sub x y)):
https://alive2.llvm.org/ce/z/QEgDaa
And changing the range to 32770 or higher there will break the
transformation

(cherry picked from commit 93030c3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:X86 llvm:SelectionDAG SelectionDAGISel as well

Projects

Development

Successfully merging this pull request may close these issues.

wrong code at -O1 and above on x86_64-linux-gnu

4 participants