[llvm] [InstCombine] Implement ((B ^ C) & A) | B -> B | (A & C) (PR #78782)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 19 12:52:35 PST 2024


https://github.com/AtariDreams created https://github.com/llvm/llvm-project/pull/78782

We already have this for the OR variant, but this works for XOR as well.

>From 6be58b3d4f2a9c65a8a1e10f2ac828f20b8dcf89 Mon Sep 17 00:00:00 2001
From: Rose <83477269+AtariDreams at users.noreply.github.com>
Date: Fri, 19 Jan 2024 13:02:20 -0500
Subject: [PATCH 1/2] [InstCombine] Pre-commit tests

---
 llvm/test/Transforms/InstCombine/or.ll | 70 ++++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 4 deletions(-)

diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 573a11599141a7..5fd1f2fbb1bf92 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -799,6 +799,68 @@ define i32 @test45_commuted3(i32 %x, i32 %y, i32 %z) {
   ret i32 %or1
 }
 
+define i32 @test45a(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test45a(
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[X:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[Y]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %xor = xor i32 %y, %z
+  %and = and i32 %x, %xor
+  %or = or i32 %and, %y
+  ret i32 %or
+}
+
+define i32 @test45a_commuted1(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test45a_commuted1(
+; CHECK-NEXT:    [[YY:%.*]] = mul i32 [[Y:%.*]], [[Y]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[YY]], [[Z:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[X:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[YY]], [[AND]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %yy = mul i32 %y, %y ; thwart complexity-based ordering
+  %xor = xor i32 %yy, %z
+  %and = and i32 %xor, %x
+  %or = or i32 %yy, %and
+  ret i32 %or
+}
+
+define i32 @test45a_commuted2(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test45a_commuted2(
+; CHECK-NEXT:    [[YY:%.*]] = mul i32 [[Y:%.*]], [[Y]]
+; CHECK-NEXT:    [[XX:%.*]] = mul i32 [[X:%.*]], [[X]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[YY]], [[Z:%.*]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XX]], [[XOR]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[YY]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %yy = mul i32 %y, %y ; thwart complexity-based ordering
+  %xx = mul i32 %x, %x ; thwart complexity-based ordering
+  %xor = xor i32 %yy, %z
+  %and = and i32 %xx, %xor
+  %or = or i32 %and, %yy
+  ret i32 %or
+}
+
+define i32 @test45a_commuted3(i32 %x, i32 %y, i32 %z) {
+; CHECK-LABEL: @test45a_commuted3(
+; CHECK-NEXT:    [[YY:%.*]] = mul i32 [[Y:%.*]], [[Y]]
+; CHECK-NEXT:    [[ZZ:%.*]] = mul i32 [[Z:%.*]], [[Z]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[ZZ]], [[YY]]
+; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[X:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[YY]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+  %yy = mul i32 %y, %y ; thwart complexity-based ordering
+  %zz = mul i32 %z, %z ; thwart complexity-based ordering
+  %xor = xor i32 %zz, %yy
+  %and = and i32 %xor, %x
+  %or = or i32 %and, %yy
+  ret i32 %or
+}
+
 define i1 @test46(i8 signext %c)  {
 ; CHECK-LABEL: @test46(
 ; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[C:%.*]], -33
@@ -1242,13 +1304,13 @@ define i1 @orn_and_cmp_4_logical(i32 %a, i32 %b, i32 %c) {
 ; The constant vectors are inverses. Make sure we can turn this into a select without crashing trying to truncate the constant to 16xi1.
 define <16 x i1> @test51(<16 x i1> %arg, <16 x i1> %arg1) {
 ; CHECK-LABEL: @test51(
-; CHECK-NEXT:    [[TMP3:%.*]] = shufflevector <16 x i1> [[ARG:%.*]], <16 x i1> [[ARG1:%.*]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 20, i32 5, i32 6, i32 23, i32 24, i32 9, i32 10, i32 27, i32 28, i32 29, i32 30, i32 31>
-; CHECK-NEXT:    ret <16 x i1> [[TMP3]]
+; CHECK-NEXT:    [[RET:%.*]] = shufflevector <16 x i1> [[ARG:%.*]], <16 x i1> [[ARG1:%.*]], <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 20, i32 5, i32 6, i32 23, i32 24, i32 9, i32 10, i32 27, i32 28, i32 29, i32 30, i32 31>
+; CHECK-NEXT:    ret <16 x i1> [[RET]]
 ;
   %tmp = and <16 x i1> %arg, <i1 true, i1 true, i1 true, i1 true, i1 false, i1 true, i1 true, i1 false, i1 false, i1 true, i1 true, i1 false, i1 false, i1 false, i1 false, i1 false>
   %tmp2 = and <16 x i1> %arg1, <i1 false, i1 false, i1 false, i1 false, i1 true, i1 false, i1 false, i1 true, i1 true, i1 false, i1 false, i1 true, i1 true, i1 true, i1 true, i1 true>
-  %tmp3 = or <16 x i1> %tmp, %tmp2
-  ret <16 x i1> %tmp3
+  %ret = or <16 x i1> %tmp, %tmp2
+  ret <16 x i1> %ret
 }
 
 ; This would infinite loop because it reaches a transform

>From 77303af21c137af9f707488d6402f3a492fdf89e Mon Sep 17 00:00:00 2001
From: Rose <83477269+AtariDreams at users.noreply.github.com>
Date: Fri, 19 Jan 2024 12:51:26 -0500
Subject: [PATCH 2/2] [InstCombine] Implement ((B ^ C) & A) | B -> B | (A & C)

We already have this for the OR variant, but this works for XOR as well.
---
 .../InstCombine/InstCombineAndOrXor.cpp       |  8 ++++++++
 llvm/test/Transforms/InstCombine/or.ll        | 20 ++++++++-----------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 5fd944a859ef09..3d1407062cf658 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3544,6 +3544,14 @@ 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));
 
+  // ((B ^ C) & A) | B -> B | (A & C)
+  if (match(Op0, m_c_And(m_c_Xor(m_Specific(Op1), m_Value(C)), m_Value(A))))
+    return BinaryOperator::CreateOr(Op1, Builder.CreateAnd(A, C));
+
+  // B | ((B ^ C) & A) -> B | (A & C)
+  if (match(Op1, m_c_And(m_c_Xor(m_Specific(Op0), m_Value(C)), m_Value(A))))
+    return BinaryOperator::CreateOr(Op0, Builder.CreateAnd(A, 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 5fd1f2fbb1bf92..8d13fe09cf3881 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -801,9 +801,8 @@ define i32 @test45_commuted3(i32 %x, i32 %y, i32 %z) {
 
 define i32 @test45a(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @test45a(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[Y:%.*]], [[Z:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[X:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[Y]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[TMP1]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %xor = xor i32 %y, %z
@@ -815,9 +814,8 @@ define i32 @test45a(i32 %x, i32 %y, i32 %z) {
 define i32 @test45a_commuted1(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @test45a_commuted1(
 ; CHECK-NEXT:    [[YY:%.*]] = mul i32 [[Y:%.*]], [[Y]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[YY]], [[Z:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[X:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[YY]], [[AND]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[YY]], [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %yy = mul i32 %y, %y ; thwart complexity-based ordering
@@ -831,9 +829,8 @@ define i32 @test45a_commuted2(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @test45a_commuted2(
 ; CHECK-NEXT:    [[YY:%.*]] = mul i32 [[Y:%.*]], [[Y]]
 ; CHECK-NEXT:    [[XX:%.*]] = mul i32 [[X:%.*]], [[X]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[YY]], [[Z:%.*]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XX]], [[XOR]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[YY]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[XX]], [[Z:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[YY]], [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %yy = mul i32 %y, %y ; thwart complexity-based ordering
@@ -848,9 +845,8 @@ define i32 @test45a_commuted3(i32 %x, i32 %y, i32 %z) {
 ; CHECK-LABEL: @test45a_commuted3(
 ; CHECK-NEXT:    [[YY:%.*]] = mul i32 [[Y:%.*]], [[Y]]
 ; CHECK-NEXT:    [[ZZ:%.*]] = mul i32 [[Z:%.*]], [[Z]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[ZZ]], [[YY]]
-; CHECK-NEXT:    [[AND:%.*]] = and i32 [[XOR]], [[X:%.*]]
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[AND]], [[YY]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[ZZ]], [[X:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[YY]], [[TMP1]]
 ; CHECK-NEXT:    ret i32 [[OR]]
 ;
   %yy = mul i32 %y, %y ; thwart complexity-based ordering



More information about the llvm-commits mailing list