[llvm] [InstCombine] Fold `((A ^ B) & C) | A` -> `A | (B & C)` (PR #76572)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 29 08:33:14 PST 2023


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/76572

Alive2: https://alive2.llvm.org/ce/z/LfpKzZ
Fixes #76554.


>From 39224022fda9b0cc0794d78fe5d08ad1096376b6 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 30 Dec 2023 00:17:00 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests for PR76554. NFC.

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

diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 573a11599141a7..b710f3afaa42c2 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1777,3 +1777,120 @@ if.then:
 if.else:
   ret i32 0
 }
+
+; Tests from PR76554
+define i32 @test_or_and_xor_constant(i32 %x, i32 %y) {
+; CHECK-LABEL: @test_or_and_xor_constant(
+; CHECK-NEXT:    [[A:%.*]] = and i32 [[X:%.*]], -2147483648
+; CHECK-NEXT:    [[B:%.*]] = xor i32 [[A]], -2147483648
+; CHECK-NEXT:    [[C:%.*]] = and i32 [[B]], [[Y:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = or i32 [[C]], [[A]]
+; CHECK-NEXT:    ret i32 [[D]]
+;
+  %a = and i32 %x, -2147483648
+  %b = xor i32 %a, -2147483648
+  %c = and i32 %b, %y
+  %d = or i32 %c, %a
+  ret i32 %d
+}
+
+define i32 @test_or_and_xor(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_commuted1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_commuted1(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %b, %a
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_commuted2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_commuted2(
+; CHECK-NEXT:    [[CC:%.*]] = mul i32 [[C:%.*]], [[C]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CC]], [[XOR]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %cc = mul i32 %c, %c
+  %xor = xor i32 %a, %b
+  %and = and i32 %cc, %xor
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_commuted3(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_commuted3(
+; CHECK-NEXT:    [[AA:%.*]] = mul i32 [[A:%.*]], [[A]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[AA]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AA]], [[AND]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %aa = mul i32 %a, %a
+  %xor = xor i32 %aa, %b
+  %and = and i32 %xor, %c
+  %or = or i32 %aa, %and
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_multiuse1(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_multiuse1(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    call void @use(i32 [[XOR]])
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  call void @use(i32 %xor)
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %a
+  ret i32 %or
+}
+
+; Negative tests
+
+define i32 @test_or_and_xor_mismatched_op(i32 %a, i32 %b, i32 %c, i32 %d) {
+; CHECK-LABEL: @test_or_and_xor_mismatched_op(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[D:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %and = and i32 %xor, %c
+  %or = or i32 %and, %d
+  ret i32 %or
+}
+
+define i32 @test_or_and_xor_multiuse2(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @test_or_and_xor_multiuse2(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT:    call void @use(i32 [[AND]])
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %a, %b
+  %and = and i32 %xor, %c
+  call void @use(i32 %and)
+  %or = or i32 %and, %a
+  ret i32 %or
+}

>From 3163e4186356c0172a73d9929a9c4f76c55c78aa Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 30 Dec 2023 00:18:24 +0800
Subject: [PATCH 2/2] [InstCombine] Fold `((A^B)&C)|A -> A|(B&C)`

---
 .../InstCombine/InstCombineAndOrXor.cpp       |  6 ++++
 llvm/test/Transforms/InstCombine/or.ll        | 30 ++++++++-----------
 2 files changed, 18 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index c03f50d75814d8..ac5bffe2633553 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3520,6 +3520,12 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
   if (match(Op1, m_c_And(m_c_Or(m_Specific(Op0), m_Value(C)), m_Value(A))))
     return BinaryOperator::CreateOr(Op0, Builder.CreateAnd(A, C));
 
+  // ((A ^ B) & C) | A -> A | (B & C)
+  if (match(&I, m_c_Or(m_Value(A),
+                       m_OneUse(m_c_And(m_c_Xor(m_Deferred(A), m_Value(B)),
+                                        m_Value(C))))))
+    return BinaryOperator::CreateOr(A, Builder.CreateAnd(B, C));
+
   if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this))
     return DeMorgan;
 
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index b710f3afaa42c2..0450255135f028 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1781,10 +1781,8 @@ if.else:
 ; Tests from PR76554
 define i32 @test_or_and_xor_constant(i32 %x, i32 %y) {
 ; CHECK-LABEL: @test_or_and_xor_constant(
-; CHECK-NEXT:    [[A:%.*]] = and i32 [[X:%.*]], -2147483648
-; CHECK-NEXT:    [[B:%.*]] = xor i32 [[A]], -2147483648
-; CHECK-NEXT:    [[C:%.*]] = and i32 [[B]], [[Y:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = or i32 [[C]], [[A]]
+; CHECK-NEXT:    [[A1:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = and i32 [[A1]], -2147483648
 ; CHECK-NEXT:    ret i32 [[D]]
 ;
   %a = and i32 %x, -2147483648
@@ -1796,9 +1794,8 @@ define i32 @test_or_and_xor_constant(i32 %x, i32 %y) {
 
 define i32 @test_or_and_xor(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @test_or_and_xor(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A:%.*]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %xor = xor i32 %a, %b
@@ -1809,9 +1806,8 @@ define i32 @test_or_and_xor(i32 %a, i32 %b, i32 %c) {
 
 define i32 @test_or_and_xor_commuted1(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @test_or_and_xor_commuted1(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[B:%.*]], [[A:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A:%.*]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %xor = xor i32 %b, %a
@@ -1823,9 +1819,8 @@ define i32 @test_or_and_xor_commuted1(i32 %a, i32 %b, i32 %c) {
 define i32 @test_or_and_xor_commuted2(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @test_or_and_xor_commuted2(
 ; CHECK-NEXT:    [[CC:%.*]] = mul i32 [[C:%.*]], [[C]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[CC]], [[XOR]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[CC]], [[B:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A:%.*]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %cc = mul i32 %c, %c
@@ -1838,9 +1833,8 @@ define i32 @test_or_and_xor_commuted2(i32 %a, i32 %b, i32 %c) {
 define i32 @test_or_and_xor_commuted3(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @test_or_and_xor_commuted3(
 ; CHECK-NEXT:    [[AA:%.*]] = mul i32 [[A:%.*]], [[A]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[AA]], [[B:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AA]], [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AA]], [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %aa = mul i32 %a, %a
@@ -1854,8 +1848,8 @@ define i32 @test_or_and_xor_multiuse1(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @test_or_and_xor_multiuse1(
 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    call void @use(i32 [[XOR]])
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[A]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[B]], [[C:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[A]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %xor = xor i32 %a, %b



More information about the llvm-commits mailing list