[llvm] [DAG] Generalize fold (not (neg x)) -> (add X, -1) (PR #154348)
guan jian via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 21 21:53:21 PDT 2025
https://github.com/rez5427 updated https://github.com/llvm/llvm-project/pull/154348
>From 3b1b408796592ce143ab956e1ddd415aa2468dd1 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/5] [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 c16ccaf926bc7..6f63b85857de2 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -9988,13 +9988,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 fd3a6572cd4ce7118929ef297dd2edcb73dce07e 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/5] 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 5f16f38c5fcc18a2547eae71108380c8fa1d3d94 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/5] 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 6f63b85857de2..63f60b5299451 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -9988,12 +9988,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 c85002d614061d1e899ba7df0d098363ec8a200a 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/5] 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 63f60b5299451..6ed342f9b922a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -9993,10 +9993,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 30181d4b12e89cc61813f2cf506e935059ff5230 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/5] Get rid of for
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 6ed342f9b922a..05ce2a4458a28 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -9996,24 +9996,16 @@ 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());
}
}
More information about the llvm-commits
mailing list