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

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 8 07:42:30 PDT 2025


https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/154348

>From 81758b461c40315d2b9e692cb39053da869f8e2a Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Tue, 19 Aug 2025 22:34:03 +0800
Subject: [PATCH 1/6] [DAG] genralize not neg x

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp   | 15 ++++++++-------
 llvm/test/CodeGen/PowerPC/setcc-to-sub.ll       | 10 +++++-----
 llvm/test/CodeGen/PowerPC/testComparesigeuc.ll  |  6 +++---
 llvm/test/CodeGen/PowerPC/testComparesigeui.ll  |  6 +++---
 llvm/test/CodeGen/PowerPC/testComparesigeus.ll  |  6 +++---
 llvm/test/CodeGen/PowerPC/testComparesileuc.ll  |  8 ++++----
 llvm/test/CodeGen/PowerPC/testComparesileui.ll  |  8 ++++----
 llvm/test/CodeGen/PowerPC/testComparesileus.ll  |  8 ++++----
 llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll |  6 +++---
 llvm/test/CodeGen/PowerPC/testComparesllgeui.ll |  6 +++---
 llvm/test/CodeGen/PowerPC/testComparesllgeus.ll |  6 +++---
 llvm/test/CodeGen/PowerPC/testComparesllleuc.ll |  8 ++++----
 llvm/test/CodeGen/PowerPC/testComparesllleui.ll |  8 ++++----
 llvm/test/CodeGen/PowerPC/testComparesllleus.ll |  8 ++++----
 llvm/test/CodeGen/X86/pr31045.ll                |  8 ++++----
 15 files changed, 59 insertions(+), 58 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 6310f7270ceaf..f8c59e58cbd1d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10001,13 +10001,14 @@ 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 or the subtract has a single use.
+  if (isAllOnesConstant(N1) && N0.getOpcode() == ISD::SUB) {
+    SDValue Y = N0.getOperand(0);
+    SDValue X = N0.getOperand(1);
+    if (isa<ConstantSDNode>(Y) || N0.hasOneUse()) {
+      SDValue NotY = DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
+      return DAG.getNode(ISD::ADD, DL, VT, X, NotY);
+    }
   }
 
   // fold (not (add X, -1)) -> (neg X)
diff --git a/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll b/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll
index 20dcb8ccf4908..d2ca198d8fcda 100644
--- a/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll
+++ b/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll
@@ -31,12 +31,12 @@ entry:
 define zeroext i1 @test2(ptr %s_a, ptr %s_b) local_unnamed_addr #0 {
 ; CHECK-LABEL: test2:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lwz 3, 0(3)
 ; CHECK-NEXT:    lwz 4, 0(4)
-; CHECK-NEXT:    rlwinm 3, 3, 0, 28, 28
+; CHECK-NEXT:    lwz 3, 0(3)
 ; CHECK-NEXT:    rlwinm 4, 4, 0, 28, 28
-; CHECK-NEXT:    sub 3, 4, 3
-; CHECK-NEXT:    not 3, 3
+; CHECK-NEXT:    rlwinm 3, 3, 0, 28, 28
+; CHECK-NEXT:    not 4, 4
+; CHECK-NEXT:    add 3, 3, 4
 ; CHECK-NEXT:    rldicl 3, 3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -76,8 +76,8 @@ define zeroext i1 @test4(ptr %s_a, ptr %s_b) local_unnamed_addr #0 {
 ; CHECK-NEXT:    lwz 4, 0(4)
 ; CHECK-NEXT:    rlwinm 3, 3, 0, 28, 28
 ; CHECK-NEXT:    rlwinm 4, 4, 0, 28, 28
-; CHECK-NEXT:    sub 3, 3, 4
 ; CHECK-NEXT:    not 3, 3
+; CHECK-NEXT:    add 3, 4, 3
 ; CHECK-NEXT:    rldicl 3, 3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll b/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll
index 37e589711f2db..6839578d45644 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_igeuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_igeuc:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -65,9 +65,9 @@ entry:
 define dso_local void @test_igeuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_igeuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
-; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeui.ll b/llvm/test/CodeGen/PowerPC/testComparesigeui.ll
index fc951124cf2a3..2d28d2ff94641 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesigeui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesigeui.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_igeui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_igeui:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_igeui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_igeui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
-; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeus.ll b/llvm/test/CodeGen/PowerPC/testComparesigeus.ll
index 522de14e4798a..e78381d937544 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesigeus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesigeus.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_igeus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_igeus:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_igeus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_igeus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
-; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesileuc.ll b/llvm/test/CodeGen/PowerPC/testComparesileuc.ll
index 1b6d1ae17c9b0..17a332d647b91 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesileuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesileuc.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_ileuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_ileuc:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
-; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_ileuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_ileuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
-; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesileui.ll b/llvm/test/CodeGen/PowerPC/testComparesileui.ll
index 4c1efde742db9..e121bdfbbcc42 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesileui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesileui.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_ileui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_ileui:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
-; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_ileui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_ileui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
-; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesileus.ll b/llvm/test/CodeGen/PowerPC/testComparesileus.ll
index 31952081f3db9..14e2a87a95292 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesileus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesileus.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_ileus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_ileus:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
-; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_ileus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_ileus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
-; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll
index 14519472ad01d..464b92e5c9169 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll
@@ -12,8 +12,8 @@
 define i64 @test_llgeuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llgeuc:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_llgeuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llgeuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
-; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll
index 6161109dbf923..31dde3c3f300e 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll
@@ -12,8 +12,8 @@
 define i64 @test_llgeui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llgeui:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_llgeui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llgeui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
-; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll
index a22def4beaf70..0d46fb9c6bf69 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll
@@ -12,8 +12,8 @@
 define i64 @test_llgeus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llgeus:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_llgeus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llgeus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r3, r4
-; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    addis r4, r2, glob at toc@ha
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll
index cfaa6e8fe1d83..a5d74ad1201db 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll
@@ -12,8 +12,8 @@
 define i64 @test_llleuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llleuc:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
-; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_llleuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llleuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
-; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleui.ll b/llvm/test/CodeGen/PowerPC/testComparesllleui.ll
index e438797cde772..1be2497b77193 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllleui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllleui.ll
@@ -12,8 +12,8 @@
 define i64 @test_llleui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llleui:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
-; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_llleui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llleui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
-; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleus.ll b/llvm/test/CodeGen/PowerPC/testComparesllleus.ll
index 53b9b8a16d503..e84e3fbb4707e 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllleus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllleus.ll
@@ -12,8 +12,8 @@
 define i64 @test_llleus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llleus:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
-; CHECK-NEXT:    not r3, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_llleus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llleus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r4, r4
+; CHECK-NEXT:    add r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
-; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/X86/pr31045.ll b/llvm/test/CodeGen/X86/pr31045.ll
index 4aa73d79d8cfc..a873fc6fd4959 100644
--- a/llvm/test/CodeGen/X86/pr31045.ll
+++ b/llvm/test/CodeGen/X86/pr31045.ll
@@ -21,11 +21,11 @@ define void @_Z1av() local_unnamed_addr #0 {
 ; CHECK-NEXT:    movl struct_obj_3+8(%rip), %eax
 ; CHECK-NEXT:    movzbl var_46(%rip), %ecx
 ; CHECK-NEXT:    movzbl var_49(%rip), %edx
-; CHECK-NEXT:    andl $1, %eax
-; CHECK-NEXT:    addl %eax, %eax
-; CHECK-NEXT:    subl %ecx, %eax
-; CHECK-NEXT:    subl %edx, %eax
+; CHECK-NEXT:    addl %ecx, %edx
 ; CHECK-NEXT:    notl %eax
+; CHECK-NEXT:    addl %eax, %eax
+; CHECK-NEXT:    orl $253, %eax
+; CHECK-NEXT:    addl %edx, %eax
 ; CHECK-NEXT:    movzbl %al, %eax
 ; CHECK-NEXT:    movw %ax, struct_obj_12+5(%rip)
 ; CHECK-NEXT:    movb $0, var_163(%rip)

>From d8354bc79eb22c41954822d56cb8e2d0413e256d Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Wed, 20 Aug 2025 15:21:25 +0800
Subject: [PATCH 2/6] Add xor sub combine test

---
 llvm/test/CodeGen/X86/xor-not-combine.ll | 44 ++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 llvm/test/CodeGen/X86/xor-not-combine.ll

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..334328bc457bb
--- /dev/null
+++ b/llvm/test/CodeGen/X86/xor-not-combine.ll
@@ -0,0 +1,44 @@
+; 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 or the subtract has a single use.
+
+; 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: Subtract has single use - should optimize
+define i32 @test_not_sub_single_use(i32 %x, i32 %y) {
+; CHECK-LABEL: test_not_sub_single_use:
+; CHECK:       # %bb.0:
+; CHECK:         notl %esi
+; CHECK-NEXT:    leal (%rsi,%rdi), %eax
+; CHECK-NEXT:    retq
+  %sub = sub i32 %y, %x
+  %not = xor i32 %sub, -1
+  ret i32 %not
+}
+
+; Negative test: Y is not constant AND subtract has multiple uses - should NOT optimize
+define i32 @test_not_sub_multiple_uses_non_constant(i32 %x, i32 %y) {
+; CHECK-LABEL: test_not_sub_multiple_uses_non_constant:
+; CHECK:       # %bb.0:
+; CHECK:         subl %edi, %esi
+; CHECK-NEXT:    movl %esi, %eax
+; CHECK-NEXT:    notl %eax
+; CHECK-NEXT:    leal (%rax,%rsi,2), %eax
+; CHECK-NEXT:    retq
+  %sub = sub i32 %y, %x
+  %not = xor i32 %sub, -1
+  %other_use = mul i32 %sub, 2  ; sub is used twice, and Y is not constant
+  %result = add i32 %not, %other_use
+  ret i32 %result
+}

>From d871de3d2ffd6bf769faa8ed176004bf127db13f Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Wed, 20 Aug 2025 16:43:25 +0800
Subject: [PATCH 3/6] Make code formatter satisfied

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index f8c59e58cbd1d..2967edea69099 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10001,12 +10001,14 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
     }
   }
 
-  // fold (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) {
+  // fold (not (sub Y, X)) -> (add X, ~Y) if Y is a constant or the subtract has
+  // a single use.
+  if (N0.getOpcode() == ISD::SUB && isAllOnesConstant(N1)) {
     SDValue Y = N0.getOperand(0);
     SDValue X = N0.getOperand(1);
     if (isa<ConstantSDNode>(Y) || N0.hasOneUse()) {
-      SDValue NotY = DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
+      SDValue NotY =
+          DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
       return DAG.getNode(ISD::ADD, DL, VT, X, NotY);
     }
   }

>From 67c2a68e6d1e6dc382d6ed8ec98faf9b0e1898bf Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Thu, 21 Aug 2025 18:38:43 +0800
Subject: [PATCH 4/6] Prevent infinite loop

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 27 ++++++++++++++++---
 llvm/test/CodeGen/X86/select_const.ll         | 12 ++++-----
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 2967edea69099..40864135462d2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10006,10 +10006,29 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
   if (N0.getOpcode() == ISD::SUB && isAllOnesConstant(N1)) {
     SDValue Y = N0.getOperand(0);
     SDValue X = N0.getOperand(1);
-    if (isa<ConstantSDNode>(Y) || N0.hasOneUse()) {
-      SDValue NotY =
-          DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
-      return DAG.getNode(ISD::ADD, DL, VT, X, NotY);
+
+    // Avoid infinite recursion with
+    // Fold (and X, (add (not Y), Z)) -> (and X, (not (sub Y, Z)))
+    bool hasAndUsers = false;
+    for (SDUse &Use : N->uses()) {
+      SDNode *User = Use.getUser();
+      if (User->getOpcode() == ISD::AND) {
+        hasAndUsers = true;
+        break;
+      }
+    }
+    if (!hasAndUsers) {
+      if (isa<ConstantSDNode>(Y) || N0.hasOneUse()) {
+        SDValue NotY =
+            DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
+        return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
+      }
+    } else {
+      if (isa<ConstantSDNode>(Y) && N0.hasOneUse()) {
+        SDValue NotY =
+            DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
+        return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
+      }
     }
   }
 
diff --git a/llvm/test/CodeGen/X86/select_const.ll b/llvm/test/CodeGen/X86/select_const.ll
index 35f4655dd6d7c..2b1c8d0564f0d 100644
--- a/llvm/test/CodeGen/X86/select_const.ll
+++ b/llvm/test/CodeGen/X86/select_const.ll
@@ -896,12 +896,12 @@ define i64 @opaque_constant(i1 %cond, i64 %x) {
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
 ; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    movl %eax, %edx
-; X86-NEXT:    andl $1, %edx
-; X86-NEXT:    negl %edx
-; X86-NEXT:    andl $1, %edx
-; X86-NEXT:    decl %eax
-; X86-NEXT:    andl $1, %eax
+; X86-NEXT:    andl	$1, %eax
+; X86-NEXT:    negl	%eax
+; X86-NEXT:    movl	%eax, %edx
+; X86-NEXT:    andl	$1, %edx
+; X86-NEXT:    notl	%eax
+; X86-NEXT:    andl	$1, %eax
 ; X86-NEXT:    xorl $1, %esi
 ; X86-NEXT:    xorl $1, %ecx
 ; X86-NEXT:    xorl %ebx, %ebx

>From 381c926d33d3cdcc7a49140caf449f5fce10a49d Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Fri, 22 Aug 2025 12:53:09 +0800
Subject: [PATCH 5/6] Get rid of for

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 17 ++++-------------
 llvm/test/CodeGen/X86/select_const.ll         | 12 ++++++------
 2 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 40864135462d2..d1fc2e8d1d802 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10009,24 +10009,15 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
 
     // Avoid infinite recursion with
     // Fold (and X, (add (not Y), Z)) -> (and X, (not (sub Y, Z)))
-    bool hasAndUsers = false;
-    for (SDUse &Use : N->uses()) {
-      SDNode *User = Use.getUser();
-      if (User->getOpcode() == ISD::AND) {
-        hasAndUsers = true;
-        break;
-      }
-    }
-    if (!hasAndUsers) {
+    if (none_of(N->users(),
+                [](SDNode *User) { return User->getOpcode() == ISD::AND; })) {
       if (isa<ConstantSDNode>(Y) || N0.hasOneUse()) {
-        SDValue NotY =
-            DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
+        SDValue NotY = DAG.getNOT(DL, Y, VT);
         return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
       }
     } else {
       if (isa<ConstantSDNode>(Y) && N0.hasOneUse()) {
-        SDValue NotY =
-            DAG.getNode(ISD::XOR, DL, VT, Y, DAG.getAllOnesConstant(DL, VT));
+        SDValue NotY = DAG.getNOT(DL, Y, VT);
         return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
       }
     }
diff --git a/llvm/test/CodeGen/X86/select_const.ll b/llvm/test/CodeGen/X86/select_const.ll
index 2b1c8d0564f0d..f57ed38101757 100644
--- a/llvm/test/CodeGen/X86/select_const.ll
+++ b/llvm/test/CodeGen/X86/select_const.ll
@@ -896,12 +896,12 @@ define i64 @opaque_constant(i1 %cond, i64 %x) {
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
 ; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    andl	$1, %eax
-; X86-NEXT:    negl	%eax
-; X86-NEXT:    movl	%eax, %edx
-; X86-NEXT:    andl	$1, %edx
-; X86-NEXT:    notl	%eax
-; X86-NEXT:    andl	$1, %eax
+; X86-NEXT:    andl $1, %eax
+; X86-NEXT:    negl %eax
+; X86-NEXT:    movl %eax, %edx
+; X86-NEXT:    andl $1, %edx
+; X86-NEXT:    notl %eax
+; X86-NEXT:    andl $1, %eax
 ; X86-NEXT:    xorl $1, %esi
 ; X86-NEXT:    xorl $1, %ecx
 ; X86-NEXT:    xorl %ebx, %ebx

>From f0e2a658f2dbee3bdb4b5a86deef29c74e617b6b Mon Sep 17 00:00:00 2001
From: Yui5427 <785369607 at qq.com>
Date: Thu, 4 Sep 2025 20:09:34 +0800
Subject: [PATCH 6/6] Remove infinite recursion checking

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 20 ++++----------
 llvm/test/CodeGen/PowerPC/setcc-to-sub.ll     | 10 +++----
 .../test/CodeGen/PowerPC/testComparesigeuc.ll |  6 ++---
 .../test/CodeGen/PowerPC/testComparesigeui.ll |  6 ++---
 .../test/CodeGen/PowerPC/testComparesigeus.ll |  6 ++---
 .../test/CodeGen/PowerPC/testComparesileuc.ll |  8 +++---
 .../test/CodeGen/PowerPC/testComparesileui.ll |  8 +++---
 .../test/CodeGen/PowerPC/testComparesileus.ll |  8 +++---
 .../CodeGen/PowerPC/testComparesllgeuc.ll     |  6 ++---
 .../CodeGen/PowerPC/testComparesllgeui.ll     |  6 ++---
 .../CodeGen/PowerPC/testComparesllgeus.ll     |  6 ++---
 .../CodeGen/PowerPC/testComparesllleuc.ll     |  8 +++---
 .../CodeGen/PowerPC/testComparesllleui.ll     |  8 +++---
 .../CodeGen/PowerPC/testComparesllleus.ll     |  8 +++---
 llvm/test/CodeGen/X86/pr31045.ll              |  8 +++---
 llvm/test/CodeGen/X86/select_const.ll         |  6 ++---
 llvm/test/CodeGen/X86/shift-i128.ll           | 21 +++++++--------
 llvm/test/CodeGen/X86/xor-not-combine.ll      | 27 +++++--------------
 18 files changed, 75 insertions(+), 101 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index d1fc2e8d1d802..a7e55516c831e 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -10001,25 +10001,15 @@ SDValue DAGCombiner::visitXOR(SDNode *N) {
     }
   }
 
-  // fold (not (sub Y, X)) -> (add X, ~Y) if Y is a constant or the subtract has
-  // a single use.
+  // 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);
 
-    // Avoid infinite recursion with
-    // Fold (and X, (add (not Y), Z)) -> (and X, (not (sub Y, Z)))
-    if (none_of(N->users(),
-                [](SDNode *User) { return User->getOpcode() == ISD::AND; })) {
-      if (isa<ConstantSDNode>(Y) || N0.hasOneUse()) {
-        SDValue NotY = DAG.getNOT(DL, Y, VT);
-        return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
-      }
-    } else {
-      if (isa<ConstantSDNode>(Y) && N0.hasOneUse()) {
-        SDValue NotY = DAG.getNOT(DL, Y, VT);
-        return DAG.getNode(ISD::ADD, DL, VT, X, NotY, N->getFlags());
-      }
+    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());
     }
   }
 
diff --git a/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll b/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll
index d2ca198d8fcda..20dcb8ccf4908 100644
--- a/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll
+++ b/llvm/test/CodeGen/PowerPC/setcc-to-sub.ll
@@ -31,12 +31,12 @@ entry:
 define zeroext i1 @test2(ptr %s_a, ptr %s_b) local_unnamed_addr #0 {
 ; CHECK-LABEL: test2:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lwz 4, 0(4)
 ; CHECK-NEXT:    lwz 3, 0(3)
-; CHECK-NEXT:    rlwinm 4, 4, 0, 28, 28
+; CHECK-NEXT:    lwz 4, 0(4)
 ; CHECK-NEXT:    rlwinm 3, 3, 0, 28, 28
-; CHECK-NEXT:    not 4, 4
-; CHECK-NEXT:    add 3, 3, 4
+; CHECK-NEXT:    rlwinm 4, 4, 0, 28, 28
+; CHECK-NEXT:    sub 3, 4, 3
+; CHECK-NEXT:    not 3, 3
 ; CHECK-NEXT:    rldicl 3, 3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -76,8 +76,8 @@ define zeroext i1 @test4(ptr %s_a, ptr %s_b) local_unnamed_addr #0 {
 ; CHECK-NEXT:    lwz 4, 0(4)
 ; CHECK-NEXT:    rlwinm 3, 3, 0, 28, 28
 ; CHECK-NEXT:    rlwinm 4, 4, 0, 28, 28
+; CHECK-NEXT:    sub 3, 3, 4
 ; CHECK-NEXT:    not 3, 3
-; CHECK-NEXT:    add 3, 4, 3
 ; CHECK-NEXT:    rldicl 3, 3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll b/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll
index 6839578d45644..37e589711f2db 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesigeuc.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_igeuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_igeuc:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -65,9 +65,9 @@ entry:
 define dso_local void @test_igeuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_igeuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeui.ll b/llvm/test/CodeGen/PowerPC/testComparesigeui.ll
index 2d28d2ff94641..fc951124cf2a3 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesigeui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesigeui.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_igeui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_igeui:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_igeui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_igeui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesigeus.ll b/llvm/test/CodeGen/PowerPC/testComparesigeus.ll
index e78381d937544..522de14e4798a 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesigeus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesigeus.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_igeus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_igeus:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_igeus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_igeus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesileuc.ll b/llvm/test/CodeGen/PowerPC/testComparesileuc.ll
index 17a332d647b91..1b6d1ae17c9b0 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesileuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesileuc.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_ileuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_ileuc:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_ileuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_ileuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesileui.ll b/llvm/test/CodeGen/PowerPC/testComparesileui.ll
index e121bdfbbcc42..4c1efde742db9 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesileui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesileui.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_ileui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_ileui:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_ileui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_ileui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesileus.ll b/llvm/test/CodeGen/PowerPC/testComparesileus.ll
index 14e2a87a95292..31952081f3db9 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesileus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesileus.ll
@@ -12,8 +12,8 @@
 define dso_local signext i32 @test_ileus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_ileus:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_ileus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_ileus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll
index 464b92e5c9169..14519472ad01d 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllgeuc.ll
@@ -12,8 +12,8 @@
 define i64 @test_llgeuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llgeuc:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_llgeuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llgeuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll
index 31dde3c3f300e..6161109dbf923 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllgeui.ll
@@ -12,8 +12,8 @@
 define i64 @test_llgeui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llgeui:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_llgeui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llgeui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll b/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll
index 0d46fb9c6bf69..a22def4beaf70 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllgeus.ll
@@ -12,8 +12,8 @@
 define i64 @test_llgeus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llgeus:
 ; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -64,9 +64,9 @@ entry:
 define dso_local void @test_llgeus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llgeus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r3, r3
-; CHECK-NEXT:    add r3, r4, r3
+; CHECK-NEXT:    sub r3, r3, r4
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll b/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll
index a5d74ad1201db..cfaa6e8fe1d83 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllleuc.ll
@@ -12,8 +12,8 @@
 define i64 @test_llleuc(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llleuc:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_llleuc_store(i8 zeroext %a, i8 zeroext %b) {
 ; CHECK-LABEL: test_llleuc_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stb r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleui.ll b/llvm/test/CodeGen/PowerPC/testComparesllleui.ll
index 1be2497b77193..e438797cde772 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllleui.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllleui.ll
@@ -12,8 +12,8 @@
 define i64 @test_llleui(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llleui:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_llleui_store(i32 zeroext %a, i32 zeroext %b) {
 ; CHECK-LABEL: test_llleui_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    stw r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/PowerPC/testComparesllleus.ll b/llvm/test/CodeGen/PowerPC/testComparesllleus.ll
index e84e3fbb4707e..53b9b8a16d503 100644
--- a/llvm/test/CodeGen/PowerPC/testComparesllleus.ll
+++ b/llvm/test/CodeGen/PowerPC/testComparesllleus.ll
@@ -12,8 +12,8 @@
 define i64 @test_llleus(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llleus:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    blr
 entry:
@@ -67,9 +67,9 @@ entry:
 define dso_local void @test_llleus_store(i16 zeroext %a, i16 zeroext %b) {
 ; CHECK-LABEL: test_llleus_store:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    not r4, r4
-; CHECK-NEXT:    add r3, r3, r4
+; CHECK-NEXT:    sub r3, r4, r3
 ; CHECK-NEXT:    addis r4, r2, glob at toc@ha
+; CHECK-NEXT:    not r3, r3
 ; CHECK-NEXT:    rldicl r3, r3, 1, 63
 ; CHECK-NEXT:    sth r3, glob at toc@l(r4)
 ; CHECK-NEXT:    blr
diff --git a/llvm/test/CodeGen/X86/pr31045.ll b/llvm/test/CodeGen/X86/pr31045.ll
index a873fc6fd4959..4aa73d79d8cfc 100644
--- a/llvm/test/CodeGen/X86/pr31045.ll
+++ b/llvm/test/CodeGen/X86/pr31045.ll
@@ -21,11 +21,11 @@ define void @_Z1av() local_unnamed_addr #0 {
 ; CHECK-NEXT:    movl struct_obj_3+8(%rip), %eax
 ; CHECK-NEXT:    movzbl var_46(%rip), %ecx
 ; CHECK-NEXT:    movzbl var_49(%rip), %edx
-; CHECK-NEXT:    addl %ecx, %edx
-; CHECK-NEXT:    notl %eax
+; CHECK-NEXT:    andl $1, %eax
 ; CHECK-NEXT:    addl %eax, %eax
-; CHECK-NEXT:    orl $253, %eax
-; CHECK-NEXT:    addl %edx, %eax
+; CHECK-NEXT:    subl %ecx, %eax
+; CHECK-NEXT:    subl %edx, %eax
+; CHECK-NEXT:    notl %eax
 ; CHECK-NEXT:    movzbl %al, %eax
 ; CHECK-NEXT:    movw %ax, struct_obj_12+5(%rip)
 ; CHECK-NEXT:    movb $0, var_163(%rip)
diff --git a/llvm/test/CodeGen/X86/select_const.ll b/llvm/test/CodeGen/X86/select_const.ll
index f57ed38101757..35f4655dd6d7c 100644
--- a/llvm/test/CodeGen/X86/select_const.ll
+++ b/llvm/test/CodeGen/X86/select_const.ll
@@ -896,11 +896,11 @@ define i64 @opaque_constant(i1 %cond, i64 %x) {
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
 ; X86-NEXT:    movzbl {{[0-9]+}}(%esp), %eax
-; X86-NEXT:    andl $1, %eax
-; X86-NEXT:    negl %eax
 ; X86-NEXT:    movl %eax, %edx
 ; X86-NEXT:    andl $1, %edx
-; X86-NEXT:    notl %eax
+; X86-NEXT:    negl %edx
+; X86-NEXT:    andl $1, %edx
+; X86-NEXT:    decl %eax
 ; X86-NEXT:    andl $1, %eax
 ; X86-NEXT:    xorl $1, %esi
 ; X86-NEXT:    xorl $1, %ecx
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
index 334328bc457bb..af65ade35ce8d 100644
--- a/llvm/test/CodeGen/X86/xor-not-combine.ll
+++ b/llvm/test/CodeGen/X86/xor-not-combine.ll
@@ -2,7 +2,7 @@
 ; 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 or the subtract has a single use.
+; 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) {
@@ -15,30 +15,15 @@ define i32 @test_not_sub_constant(i32 %x) {
   ret i32 %not
 }
 
-; Test case 2: Subtract has single use - should optimize
-define i32 @test_not_sub_single_use(i32 %x, i32 %y) {
-; CHECK-LABEL: test_not_sub_single_use:
+; 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:         notl %esi
-; CHECK-NEXT:    leal (%rsi,%rdi), %eax
-; CHECK-NEXT:    retq
-  %sub = sub i32 %y, %x
-  %not = xor i32 %sub, -1
-  ret i32 %not
-}
-
-; Negative test: Y is not constant AND subtract has multiple uses - should NOT optimize
-define i32 @test_not_sub_multiple_uses_non_constant(i32 %x, i32 %y) {
-; CHECK-LABEL: test_not_sub_multiple_uses_non_constant:
-; CHECK:       # %bb.0:
-; CHECK:         subl %edi, %esi
 ; CHECK-NEXT:    movl %esi, %eax
+; CHECK-NEXT:    subl %edi, %eax
 ; CHECK-NEXT:    notl %eax
-; CHECK-NEXT:    leal (%rax,%rsi,2), %eax
 ; CHECK-NEXT:    retq
   %sub = sub i32 %y, %x
   %not = xor i32 %sub, -1
-  %other_use = mul i32 %sub, 2  ; sub is used twice, and Y is not constant
-  %result = add i32 %not, %other_use
-  ret i32 %result
+  ret i32 %not
 }



More information about the llvm-commits mailing list