[llvm] 83af24d - [DAG] Generalize fold (not (neg x)) -> (add X, -1) (#154348)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 8 08:13:04 PDT 2025


Author: guan jian
Date: 2025-09-08T15:12:59Z
New Revision: 83af24dd85b0a6cf764e69769bf8ab1a49b02cf5

URL: https://github.com/llvm/llvm-project/commit/83af24dd85b0a6cf764e69769bf8ab1a49b02cf5
DIFF: https://github.com/llvm/llvm-project/commit/83af24dd85b0a6cf764e69769bf8ab1a49b02cf5.diff

LOG: [DAG] Generalize fold (not (neg x)) -> (add X, -1) (#154348)

Generalize `fold (not (neg x)) -> (add X, -1)` to `fold (not (sub Y, X)) -> (add X, ~Y)`

---------

Co-authored-by: Yui5427 <785369607 at qq.com>
Co-authored-by: Simon Pilgrim <llvm-dev at redking.me.uk>

Added: 
    llvm/test/CodeGen/X86/xor-not-combine.ll

Modified: 
    llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
    llvm/test/CodeGen/X86/shift-i128.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 1ef2b35952833..d130efe96b56b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10001,13 +10001,16 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
     }
   }
 
-  // fold (not (neg x)) -> (add X, -1)
-  // FIXME: This can be generalized to (not (sub Y, X)) -> (add X, ~Y) if
-  // Y is a constant or the subtract has a single use.
-  if (isAllOnesConstant(N1) && N0.getOpcode() == ISD::SUB &&
-      isNullConstant(N0.getOperand(0))) {
-    return DAG.getNode(ISD::ADD, DL, VT, N0.getOperand(1),
-                       DAG.getAllOnesConstant(DL, VT));
+  // fold (not (sub Y, X)) -> (add X, ~Y) if Y is a constant
+  if (N0.getOpcode() == ISD::SUB && isAllOnesConstant(N1)) {
+    SDValue Y = N0.getOperand(0);
+    SDValue X = N0.getOperand(1);
+
+    if (auto *YConst = dyn_cast<ConstantSDNode>(Y)) {
+      APInt NotYValue = ~YConst->getAPIntValue();
+      SDValue NotY = DAG.getConstant(NotYValue, DL, VT);
+      return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
+    }
   }
 
   // fold (not (add X, -1)) -> (neg X)

diff  --git a/llvm/test/CodeGen/X86/shift-i128.ll b/llvm/test/CodeGen/X86/shift-i128.ll
index a82656e4b7147..7462c77482827 100644
--- a/llvm/test/CodeGen/X86/shift-i128.ll
+++ b/llvm/test/CodeGen/X86/shift-i128.ll
@@ -949,21 +949,20 @@ define i128 @shift_i128_limited_shamt(i128 noundef %a, i32 noundef %b) nounwind
 ; i686-NEXT:    pushl %esi
 ; i686-NEXT:    andl $-16, %esp
 ; i686-NEXT:    subl $16, %esp
-; i686-NEXT:    movl 28(%ebp), %esi
-; i686-NEXT:    movl 32(%ebp), %eax
+; i686-NEXT:    movl 32(%ebp), %ebx
+; i686-NEXT:    movl 28(%ebp), %edi
+; i686-NEXT:    movzbl 40(%ebp), %ecx
 ; i686-NEXT:    movb $6, %dl
-; i686-NEXT:    subb 40(%ebp), %dl
+; i686-NEXT:    subb %cl, %dl
+; i686-NEXT:    addb $-7, %cl
+; i686-NEXT:    movl %edi, %eax
+; i686-NEXT:    shrl %eax
+; i686-NEXT:    shrl %cl, %eax
 ; i686-NEXT:    movl %edx, %ecx
-; i686-NEXT:    shll %cl, %eax
-; i686-NEXT:    movl %esi, %ebx
-; i686-NEXT:    movl %esi, %edi
-; i686-NEXT:    shrl %ebx
-; i686-NEXT:    notb %cl
-; i686-NEXT:    shrl %cl, %ebx
+; i686-NEXT:    shll %cl, %ebx
 ; i686-NEXT:    orl %eax, %ebx
 ; i686-NEXT:    movl 24(%ebp), %esi
 ; i686-NEXT:    movl %esi, %eax
-; i686-NEXT:    movl %edx, %ecx
 ; i686-NEXT:    shll %cl, %eax
 ; i686-NEXT:    shldl %cl, %esi, %edi
 ; i686-NEXT:    movl %edi, {{[-0-9]+}}(%e{{[sb]}}p) # 4-byte Spill
@@ -972,10 +971,10 @@ define i128 @shift_i128_limited_shamt(i128 noundef %a, i32 noundef %b) nounwind
 ; i686-NEXT:    movl 32(%ebp), %edx
 ; i686-NEXT:    shldl %cl, %edx, %esi
 ; i686-NEXT:    movl %esi, 12(%edi)
+; i686-NEXT:    movl %ebx, 8(%edi)
 ; i686-NEXT:    movl {{[-0-9]+}}(%e{{[sb]}}p), %ecx # 4-byte Reload
 ; i686-NEXT:    movl %ecx, 4(%edi)
 ; i686-NEXT:    movl %eax, (%edi)
-; i686-NEXT:    movl %ebx, 8(%edi)
 ; i686-NEXT:    movl %edi, %eax
 ; i686-NEXT:    leal -12(%ebp), %esp
 ; i686-NEXT:    popl %esi

diff  --git a/llvm/test/CodeGen/X86/xor-not-combine.ll b/llvm/test/CodeGen/X86/xor-not-combine.ll
new file mode 100644
index 0000000000000..af65ade35ce8d
--- /dev/null
+++ b/llvm/test/CodeGen/X86/xor-not-combine.ll
@@ -0,0 +1,29 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s
+
+; Test for DAG combine: fold (not (sub Y, X)) -> (add X, ~Y)
+; when Y is a constant.
+
+; Test case 1: Y is a constant - should transform to (add X, ~Y)
+define i32 @test_not_sub_constant(i32 %x) {
+; CHECK-LABEL: test_not_sub_constant:
+; CHECK:       # %bb.0:
+; CHECK:         leal -101(%rdi), %eax
+; CHECK-NEXT:    retq
+  %sub = sub i32 100, %x
+  %not = xor i32 %sub, -1
+  ret i32 %not
+}
+
+; Test case 2: Y is not a constant - should NOT optimize
+define i32 @test_not_sub_non_constant(i32 %x, i32 %y) {
+; CHECK-LABEL: test_not_sub_non_constant:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %eax
+; CHECK-NEXT:    subl %edi, %eax
+; CHECK-NEXT:    notl %eax
+; CHECK-NEXT:    retq
+  %sub = sub i32 %y, %x
+  %not = xor i32 %sub, -1
+  ret i32 %not
+}


        


More information about the llvm-commits mailing list