From 5aad118341cf919bd6d08298064129568a92591c Mon Sep 17 00:00:00 2001 From: guan jian <148229859+rez5427@users.noreply.github.com> Date: Mon, 8 Sep 2025 23:12:59 +0800 Subject: [PATCH] [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)` --------- --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 17 ++++++----- llvm/test/CodeGen/X86/xor-not-combine.ll | 29 +++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 llvm/test/CodeGen/X86/xor-not-combine.ll diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 7b1f1dc40211..02e8bc9fc211 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -9521,13 +9521,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(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/xor-not-combine.ll b/llvm/test/CodeGen/X86/xor-not-combine.ll new file mode 100644 index 000000000000..af65ade35ce8 --- /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 +} -- Gitee