[llvm] [InstCombine] Fold Xor with or disjoint (PR #105992)

Amr Hesham via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 30 10:41:02 PDT 2024


https://github.com/AmrDeveloper updated https://github.com/llvm/llvm-project/pull/105992

>From 4a995d208c3386d619014738fd938f815eb8e7e2 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Thu, 29 Aug 2024 19:21:19 +0200
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests

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

diff --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll
index ea7f7382ee7c8e..63ffa87372a779 100644
--- a/llvm/test/Transforms/InstCombine/xor.ll
+++ b/llvm/test/Transforms/InstCombine/xor.ll
@@ -1485,3 +1485,111 @@ define i4 @PR96857_xor_without_noundef(i4  %val0, i4  %val1, i4 %val2) {
   %val7 = xor i4 %val4, %val6
   ret i4 %val7
 }
+
+define i32 @or_disjoint_with_xor(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @or_disjoint_with_xor(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+entry:
+  %or = or disjoint i32 %a, %b
+  %xor = xor i32 %or, %c
+  ret i32 %xor
+}
+
+define i32 @xor_with_or_disjoint(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @xor_with_or_disjoint(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[C:%.*]], [[OR]]
+; CHECK-NEXT:    ret i32 [[XOR]]
+;
+entry:
+  %or = or disjoint i32 %a, %b
+  %xor = xor i32 %c, %or
+  ret i32 %xor
+}
+
+define <2 x i32> @or_disjoint_with_xor_vec(<2 x i32> %a, < 2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @or_disjoint_with_xor_vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[OR]], [[C:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[XOR]]
+;
+entry:
+  %or = or disjoint <2 x i32> %a, %b
+  %xor = xor <2 x i32> %or, %c
+  ret <2 x i32> %xor
+}
+
+define <2 x i32> @xor_with_or_disjoint_vec(<2 x i32> %a, < 2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @xor_with_or_disjoint_vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[C:%.*]], [[OR]]
+; CHECK-NEXT:    ret <2 x i32> [[XOR]]
+;
+entry:
+  %or = or disjoint <2 x i32> %a, %b
+  %xor = xor <2 x i32> %c, %or
+  ret <2 x i32> %xor
+}
+
+define i32 @or_multi_use_disjoint_with_xor(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @or_multi_use_disjoint_with_xor(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[OR]], [[XOR]]
+; CHECK-NEXT:    ret i32 [[ADD]]
+;
+entry:
+  %or = or disjoint i32 %a, %b
+  %xor = xor i32 %or, %c
+  %add = add i32 %or, %xor
+  ret i32 %add
+}
+
+define <2 x i32> @or_multi_use_disjoint_with_xor_vec(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @or_multi_use_disjoint_with_xor_vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[OR]], [[C:%.*]]
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[OR]], [[XOR]]
+; CHECK-NEXT:    ret <2 x i32> [[ADD]]
+;
+entry:
+  %or = or disjoint <2 x i32> %a, %b
+  %xor = xor <2 x i32> %or, %c
+  %add = add <2 x i32> %or, %xor
+  ret <2 x i32> %add
+}
+
+define i32 @add_with_or(i32 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @add_with_or(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or i32 [[ADD]], [[C:%.*]]
+; CHECK-NEXT:    ret i32 [[OR]]
+;
+entry:
+  %add = add i32 %a, %b
+  %or = or i32 %add, %c
+  ret i32 %or
+}
+
+define <2 x i32> @add_with_or_vec(<2 x i32> %a, <2 x i32> %b, <2 x i32> %c) {
+; CHECK-LABEL: @add_with_or_vec(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT:    [[OR:%.*]] = or <2 x i32> [[ADD]], [[C:%.*]]
+; CHECK-NEXT:    ret <2 x i32> [[OR]]
+;
+entry:
+  %add = add <2 x i32> %a, %b
+  %or = or <2 x i32> %add, %c
+  ret <2 x i32> %or
+}

>From b2ecae045a3d93a24e6aa27f439cf458d8fbf2a8 Mon Sep 17 00:00:00 2001
From: AmrDeveloper <amr96 at programmer.net>
Date: Fri, 30 Aug 2024 19:30:19 +0200
Subject: [PATCH 2/2] [InstCombine] Fold Xor with or disjoint

Implement a missing optimization to fold (A | B) ^ C to (A ^ C) ^ B
---
 .../InstCombine/InstCombineAndOrXor.cpp          |  8 ++++++++
 .../InstCombine/2010-11-01-lshr-mask.ll          |  6 +++---
 .../test/Transforms/InstCombine/icmp-of-xor-x.ll | 12 ++++++------
 llvm/test/Transforms/InstCombine/xor.ll          | 16 ++++++++--------
 4 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 4f557532f9f783..83955d6a3c63dd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -4706,6 +4706,14 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) {
     return Xor;
 
   Value *X, *Y;
+
+  // (A | B) ^ C -> (A ^ C) ^ B
+  // C ^ (A | B) -> B ^ (A ^ C)
+  if (match(&I, m_c_Xor(m_OneUse(m_c_DisjointOr(m_Value(X), m_Value(Y))), m_Value(M)))) {
+    Value *XorAC = Builder.CreateXor(X, M);
+    return BinaryOperator::CreateXor(XorAC, Y);
+  }
+
   Constant *C1;
   if (match(Op1, m_Constant(C1))) {
     Constant *C2;
diff --git a/llvm/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll b/llvm/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll
index ccbafbb197b666..6e579e462b53a9 100644
--- a/llvm/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll
+++ b/llvm/test/Transforms/InstCombine/2010-11-01-lshr-mask.ll
@@ -33,12 +33,12 @@ define i8 @foo(i8 %arg, i8 %arg1) {
 ; CHECK-NEXT:    [[T4:%.*]] = and i8 [[ARG1]], 33
 ; CHECK-NEXT:    [[T5:%.*]] = sub nsw i8 40, [[T2]]
 ; CHECK-NEXT:    [[T6:%.*]] = and i8 [[T5]], 84
-; CHECK-NEXT:    [[T7:%.*]] = or disjoint i8 [[T4]], [[T6]]
 ; CHECK-NEXT:    [[T8:%.*]] = xor i8 [[T]], [[T3]]
-; CHECK-NEXT:    [[T9:%.*]] = or disjoint i8 [[T7]], [[T8]]
 ; CHECK-NEXT:    [[TMP1:%.*]] = lshr i8 [[T8]], 2
 ; CHECK-NEXT:    [[T11:%.*]] = and i8 [[TMP1]], 32
-; CHECK-NEXT:    [[T12:%.*]] = xor i8 [[T11]], [[T9]]
+; CHECK-NEXT:    [[TMP2:%.*]] = xor i8 [[T4]], [[T11]]
+; CHECK-NEXT:    [[TMP3:%.*]] = or disjoint i8 [[TMP2]], [[T6]]
+; CHECK-NEXT:    [[T12:%.*]] = or disjoint i8 [[TMP3]], [[T8]]
 ; CHECK-NEXT:    ret i8 [[T12]]
 ;
   %t = shl i8 %arg, 7
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
index a4e7acbca930dc..f6e0493c02dba5 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll
@@ -358,8 +358,8 @@ define i1 @xor_ugt_2(i8 %xx, i8 %y, i8 %z) {
 ; CHECK-LABEL: @xor_ugt_2(
 ; CHECK-NEXT:    [[X:%.*]] = add i8 [[XX:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    [[YZ:%.*]] = and i8 [[Y:%.*]], 63
-; CHECK-NEXT:    [[Y1:%.*]] = or disjoint i8 [[YZ]], 64
-; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[X]], [[Y1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[YZ]], [[X]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i8 [[TMP1]], 64
 ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[X]], [[XOR]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
@@ -385,8 +385,8 @@ define i1 @xor_ult(i8 %x) {
 define <2 x i1> @xor_sgt(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @xor_sgt(
 ; CHECK-NEXT:    [[YZ:%.*]] = and <2 x i8> [[Y:%.*]], <i8 31, i8 31>
-; CHECK-NEXT:    [[Y1:%.*]] = or disjoint <2 x i8> [[YZ]], <i8 64, i8 64>
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[X:%.*]], [[Y1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[YZ]], [[X:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[TMP1]], <i8 64, i8 64>
 ; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[XOR]], [[X]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
@@ -400,8 +400,8 @@ define <2 x i1> @xor_sgt(<2 x i8> %x, <2 x i8> %y) {
 define <2 x i1> @xor_sgt_fail_no_known_msb(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @xor_sgt_fail_no_known_msb(
 ; CHECK-NEXT:    [[YZ:%.*]] = and <2 x i8> [[Y:%.*]], <i8 55, i8 55>
-; CHECK-NEXT:    [[Y1:%.*]] = or disjoint <2 x i8> [[YZ]], <i8 8, i8 8>
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[X:%.*]], [[Y1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor <2 x i8> [[YZ]], [[X:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[TMP1]], <i8 8, i8 8>
 ; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[XOR]], [[X]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/xor.ll b/llvm/test/Transforms/InstCombine/xor.ll
index 63ffa87372a779..78a34e64289264 100644
--- a/llvm/test/Transforms/InstCombine/xor.ll
+++ b/llvm/test/Transforms/InstCombine/xor.ll
@@ -1489,8 +1489,8 @@ define i4 @PR96857_xor_without_noundef(i4  %val0, i4  %val1, i4 %val2) {
 define i32 @or_disjoint_with_xor(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @or_disjoint_with_xor(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP0:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[TMP0]], [[B:%.*]]
 ; CHECK-NEXT:    ret i32 [[XOR]]
 ;
 entry:
@@ -1502,8 +1502,8 @@ entry:
 define i32 @xor_with_or_disjoint(i32 %a, i32 %b, i32 %c) {
 ; CHECK-LABEL: @xor_with_or_disjoint(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[C:%.*]], [[OR]]
+; CHECK-NEXT:    [[TMP0:%.*]] = xor i32 [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[TMP0]], [[B:%.*]]
 ; CHECK-NEXT:    ret i32 [[XOR]]
 ;
 entry:
@@ -1515,8 +1515,8 @@ entry:
 define <2 x i32> @or_disjoint_with_xor_vec(<2 x i32> %a, < 2 x i32> %b, <2 x i32> %c) {
 ; CHECK-LABEL: @or_disjoint_with_xor_vec(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[OR]], [[C:%.*]]
+; CHECK-NEXT:    [[TMP0:%.*]] = xor <2 x i32> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[TMP0]], [[B:%.*]]
 ; CHECK-NEXT:    ret <2 x i32> [[XOR]]
 ;
 entry:
@@ -1528,8 +1528,8 @@ entry:
 define <2 x i32> @xor_with_or_disjoint_vec(<2 x i32> %a, < 2 x i32> %b, <2 x i32> %c) {
 ; CHECK-LABEL: @xor_with_or_disjoint_vec(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[OR:%.*]] = or disjoint <2 x i32> [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[C:%.*]], [[OR]]
+; CHECK-NEXT:    [[TMP0:%.*]] = xor <2 x i32> [[A:%.*]], [[C:%.*]]
+; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i32> [[TMP0]], [[B:%.*]]
 ; CHECK-NEXT:    ret <2 x i32> [[XOR]]
 ;
 entry:



More information about the llvm-commits mailing list