[llvm] [InstCombine] Fold (A & B) - (A & ~B) --> B - (A ^ B) (PR #79717)

via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 11 19:29:47 PST 2024


https://github.com/AtariDreams updated https://github.com/llvm/llvm-project/pull/79717

>From b7aba083a3316a3bd8cab49cd9d4762bca2a1946 Mon Sep 17 00:00:00 2001
From: Rose <83477269+AtariDreams at users.noreply.github.com>
Date: Sat, 27 Jan 2024 16:40:49 -0500
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests (NFC)

---
 llvm/test/Transforms/InstCombine/sub.ll | 30 +++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll
index 494cdf62c7975e..720d86a3159b27 100644
--- a/llvm/test/Transforms/InstCombine/sub.ll
+++ b/llvm/test/Transforms/InstCombine/sub.ll
@@ -2626,3 +2626,33 @@ define i8 @sub_of_adds_2xc(i8 %x, i8 %y) {
   %r = sub i8 %xc, %yc
   ret i8 %r
 }
+
+define i32 @sub_and_xor(i32 %A, i32 %B) {
+; CHECK-LABEL: @sub_and_xor(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], -1
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[XOR]], [[A:%.*]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[B]], [[A]]
+; CHECK-NEXT:    [[RES:%.*]] = sub nsw i32 [[AND1]], [[AND2]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %xor = xor i32 %B, -1
+  %and1 = and i32 %xor, %A
+  %and2 = and i32 %B, %A
+  %res = sub nsw i32 %and1, %and2
+  ret i32 %res
+}
+
+define i32 @sub_xor_and(i32 %A, i32 %B) {
+; CHECK-LABEL: @sub_xor_and(
+; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B]], -1
+; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR]], [[A]]
+; CHECK-NEXT:    [[RES:%.*]] = sub nsw i32 [[AND1]], [[AND2]]
+; CHECK-NEXT:    ret i32 [[RES]]
+;
+  %and1 = and i32 %B, %A
+  %xor = xor i32 %B, -1
+  %and2 = and i32 %xor, %A
+  %res = sub nsw i32 %and1, %and2
+  ret i32 %res
+}

>From d54ca47f49a32826d114efd0b138252e14416724 Mon Sep 17 00:00:00 2001
From: Rose <83477269+AtariDreams at users.noreply.github.com>
Date: Sat, 27 Jan 2024 19:44:23 -0500
Subject: [PATCH 2/2] [InstCombine] Fold (A & B) - (A & ~B) --> B - (A ^ B)

(A & B) - (A & ~B) --> B - (A ^ B), and (A & ~B) - (A & B) --> (A ^ B) - B

Alive2 Proof:
https://alive2.llvm.org/ce/z/DWVWYy
---
 .../InstCombine/InstCombineAddSub.cpp         | 26 +++++++++++++++++++
 llvm/test/Transforms/InstCombine/sub.ll       | 12 +++------
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index cfff5df9ff5005..fe0d73ca9426a3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2371,6 +2371,32 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
       return BinaryOperator::CreateNeg(Y);
   }
 
+  {
+    Value *A, *B;
+    // (A & ~B) - (A & B) --> (A ^ B) - B
+    if (match(Op0, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
+        match(Op1, m_c_And(m_Specific(A), m_Specific(B)))) {
+      BinaryOperator *Res =
+          BinaryOperator::CreateSub(Builder.CreateXor(A, B), B);
+      // Propagate nsw flags
+      Res->setHasNoSignedWrap(I.hasNoSignedWrap());
+      return Res;
+    }
+  }
+
+  {
+    Value *A, *B;
+    // (A & B) - (A & ~B) --> B - (A ^ B)
+    if (match(Op1, m_c_And(m_Value(A), m_Not(m_Value(B)))) &&
+        match(Op0, m_c_And(m_Specific(A), m_Specific(B)))) {
+      BinaryOperator *Res =
+          BinaryOperator::CreateSub(B, Builder.CreateXor(A, B));
+      // Propagate nsw flags
+      Res->setHasNoSignedWrap(I.hasNoSignedWrap());
+      return Res;
+    }
+  }
+
   // (sub (or A, B) (and A, B)) --> (xor A, B)
   {
     Value *A, *B;
diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll
index 720d86a3159b27..e09fb31089855c 100644
--- a/llvm/test/Transforms/InstCombine/sub.ll
+++ b/llvm/test/Transforms/InstCombine/sub.ll
@@ -2629,10 +2629,8 @@ define i8 @sub_of_adds_2xc(i8 %x, i8 %y) {
 
 define i32 @sub_and_xor(i32 %A, i32 %B) {
 ; CHECK-LABEL: @sub_and_xor(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], -1
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[XOR]], [[A:%.*]]
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[B]], [[A]]
-; CHECK-NEXT:    [[RES:%.*]] = sub nsw i32 [[AND1]], [[AND2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = sub nsw i32 [[TMP1]], [[B]]
 ; CHECK-NEXT:    ret i32 [[RES]]
 ;
   %xor = xor i32 %B, -1
@@ -2644,10 +2642,8 @@ define i32 @sub_and_xor(i32 %A, i32 %B) {
 
 define i32 @sub_xor_and(i32 %A, i32 %B) {
 ; CHECK-LABEL: @sub_xor_and(
-; CHECK-NEXT:    [[AND1:%.*]] = and i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B]], -1
-; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[XOR]], [[A]]
-; CHECK-NEXT:    [[RES:%.*]] = sub nsw i32 [[AND1]], [[AND2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = sub nsw i32 [[B]], [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[RES]]
 ;
   %and1 = and i32 %B, %A



More information about the llvm-commits mailing list