Skip to content

[DAG] Fold (bitwiseop X, (add (not Y), Z)) -> (bitwiseop X, (not (sub Y, Z))). #141476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

simonzgx
Copy link
Contributor

@simonzgx simonzgx commented May 26, 2025

Fixes #140639

@llvmbot llvmbot added the llvm:SelectionDAG SelectionDAGISel as well label May 26, 2025
@simonzgx simonzgx marked this pull request as draft May 26, 2025 11:19
@llvmbot
Copy link
Member

llvmbot commented May 26, 2025

@llvm/pr-subscribers-backend-x86
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-backend-loongarch

@llvm/pr-subscribers-llvm-selectiondag

Author: Xu Zhang (simonzgx)

Changes

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

1 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+7)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index efaa8bd4a7950..31fbab23e4fcf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -7528,6 +7528,13 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
       return DAG.getNode(ISD::AND, DL, VT, X,
                          DAG.getNOT(DL, DAG.getNode(Opc, DL, VT, Y, Z), VT));
 
+  // a bitwiseop (~b + c) -> a bitwiseop ~(b - c).
+  // Fold (and X, (add (not Y), Z)) -> (and X, (not (sub Y, Z)))
+  if (sd_match(N, m_And(m_Value(X), m_Add(m_Value(NotY), m_Value(Z)))) &&
+      sd_match(NotY, m_Not(m_Value(Y))) &&
+      (TLI.hasAndNot(SDValue(N, 0)) || NotY->hasOneUse())) {
+		return DAG.getNode(ISD::AND, DL, VT, X, DAG.getNOT(DL, DAG.getNode(ISD::SUB, DL, VT, Y, Z), VT));
+  }
   // Fold (and (srl X, C), 1) -> (srl X, BW-1) for signbit extraction
   // If we are shifting down an extended sign bit, see if we can simplify
   // this to shifting the MSB directly to expose further simplifications.

Copy link

github-actions bot commented May 26, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@jayfoad
Copy link
Contributor

jayfoad commented May 27, 2025

As well as ~y+z --> ~(y-z) you can also do ~y-z --> ~(y+z) right?

@RKSimon RKSimon requested review from jayfoad, arsenm and RKSimon May 27, 2025 11:11
Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

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

Needs tests

@simonzgx
Copy link
Contributor Author

Needs tests

Yes, there are some failed UT that need fixing and some new ones to add. I'm still working on both and will submit soon.

@simonzgx simonzgx changed the title [WIP] Fold (bitwiseop X, (add (not Y), Z)) -> (bitwiseop X, (not (sub Y, Z))). [DAG] Fold (bitwiseop X, (add (not Y), Z)) -> (bitwiseop X, (not (sub Y, Z))). May 29, 2025
@simonzgx simonzgx marked this pull request as ready for review May 29, 2025 11:10
@simonzgx simonzgx requested review from arsenm and RKSimon May 29, 2025 11:11
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc < %s -mtriple=aarch64-linux | FileCheck %s

define i8 @andnot_add_with_neg_i8(i8 %0, i8 %1) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

(style) if you can its preferred to avoid numbered variables (also means you can drop the entry: labels).

@@ -11609,6 +11625,28 @@ SDValue DAGCombiner::foldShiftToAvg(SDNode *N) {
return DAG.getNode(FloorISD, SDLoc(N), N->getValueType(0), {A, B});
}

SDValue DAGCombiner::foldBitwiseOpWithNeg(SDNode *N, const SDLoc &DL, EVT VT) {
if (!TLI.hasAndNot(SDValue(N, 0)))
Copy link
Collaborator

Choose a reason for hiding this comment

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

We're checking for ANDNOT instructions but we're also folding to ORNOT and XORNOT patterns?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

a & ~(a - b) optimizes to a & (~a + b) even though most targets have an ANDN instruction
5 participants