[llvm] [InstSimplify] Simplify select if it combinated `and/or/xor` (PR #73362)

via llvm-commits llvm-commits at lists.llvm.org
Mon Nov 27 01:35:36 PST 2023


https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/73362

>From c200abdf4d0dde6ebeda3a40da0572b687e8abf1 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Mon, 27 Nov 2023 09:11:03 +0900
Subject: [PATCH 1/2] [InstSimplify] Add test for simplify select if it
 combinated and/or/xor

- (X & Y) == 0 ? X | Y : X ^ Y   --> X ^ Y
- (X & Y) != 0 ? X | Y : X ^ Y   --> X | Y
- (X | Y) == 0 ? X & Y : X ^ Y   --> X ^ Y
- (X | Y) != 0 ? X & Y : X ^ Y   --> X & Y
- (X ^ Y) == 0 ? X | Y : X & Y   --> X & Y
- (X ^ Y) != 0 ? X | Y : X & Y   --> X | Y

certain combinations of bitwise operators can be simplified to
returning the value of the True or False clause.

Proofs : https://alive2.llvm.org/ce/z/9jidcw

Fixed #71792.
---
 llvm/test/Transforms/InstSimplify/select.ll | 146 ++++++++++++++++++++
 1 file changed, 146 insertions(+)

diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll
index c85c4d03000feaf..2adcf2d85356103 100644
--- a/llvm/test/Transforms/InstSimplify/select.ll
+++ b/llvm/test/Transforms/InstSimplify/select.ll
@@ -1652,3 +1652,149 @@ define i8 @select_xor_cmp_unmatched_operands(i8 %0, i8 %1, i8 %c) {
   %5 = select i1 %3, i8 0, i8 %4
   ret i8 %5
 }
+
+; Select icmp and/or/xor
+; X&Y==0 ? X|Y : X^Y  -> X|Y
+define i32 @src_select_and0_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and0_or_xor(
+; CHECK-NEXT:   [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[XOR:%.*]]
+  %and = and i32 %x, %y
+  %and0 = icmp eq i32 %and, 0
+  %xor = xor i32 %x, %y
+  %or = or i32 %x, %y
+  %cond = select i1 %and0, i32 %or, i32 %xor
+  ret i32 %cond
+}
+; X&Y==0 ? X^Y : X|Y  -> X|Y
+define i32 @src_select_and0_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and0_xor_or(
+; CHECK-NEXT:   [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[OR:%.*]]
+  %and = and i32 %x, %y
+  %and0 = icmp eq i32 %and, 0
+  %xor = xor i32 %x, %y
+  %or = or i32 %x, %y
+  %cond = select i1 %and0, i32 %xor, i32 %or
+  ret i32 %cond
+}
+; X&Y!=0 ? X|Y : X^Y  -> X|Y
+define i32 @src_select_and1_or_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and1_or_xor(
+; CHECK-NEXT:   [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[OR:%.*]]
+  %and = and i32 %x, %y
+  %and1 = icmp ne i32 %and, 0
+  %xor = xor i32 %x, %y
+  %or = or i32 %x, %y
+  %cond = select i1 %and1, i32 %or, i32 %xor
+  ret i32 %cond
+}
+; X&Y!=0 ? X^Y : X|Y  -> X^Y
+define i32 @src_select_and1_xor_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_and1_xor_or(
+; CHECK-NEXT:   [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[XOR:%.*]]
+  %and = and i32 %x, %y
+  %and1 = icmp ne i32 %and, 0
+  %xor = xor i32 %x, %y
+  %or = or i32 %x, %y
+  %cond = select i1 %and1, i32 %xor, i32 %or
+  ret i32 %cond
+}
+; X|Y==0 ? X&Y : X^Y  -> X^Y
+define i32 @src_select_or0_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or0_and_xor(
+; CHECK-NEXT:   [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[XOR:%.*]]
+  %or = or i32 %x, %y
+  %or0 = icmp eq i32 %or, 0
+  %xor = xor i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %or0, i32 %and, i32 %xor
+  ret i32 %cond
+}
+; X|Y!=0 ? X&Y : X^Y  -> X&Y
+define i32 @src_select_or1_and_xor(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or1_and_xor(
+; CHECK-NEXT:   [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[AND:%.*]]
+  %or = or i32 %x, %y
+  %or1 = icmp ne i32 %or, 0
+  %xor = xor i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %or1, i32 %and, i32 %xor
+  ret i32 %cond
+}
+; X|Y==0 ? X^Y : X&Y  -> X&Y
+define i32 @src_select_or0_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or0_xor_and(
+; CHECK-NEXT:   [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[AND:%.*]]
+  %or = or i32 %x, %y
+  %or0 = icmp eq i32 %or, 0
+  %xor = xor i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %or0, i32 %xor, i32 %and
+  ret i32 %cond
+}
+; X|Y==0 ? X^Y : X&Y  -> X&Y
+define i32 @src_select_or1_xor_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_or1_xor_and(
+; CHECK-NEXT:   [[XOR:%.*]] = xor i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[XOR:%.*]]
+  %or = or i32 %x, %y
+  %or1 = icmp ne i32 %or, 0
+  %xor = xor i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %or1, i32 %xor, i32 %and
+  ret i32 %cond
+}
+; X^Y==0 ? X&Y : X|Y  -> X|Y
+define i32 @src_select_xor0_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor0_and_or(
+; CHECK-NEXT:   [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[OR:%.*]]
+  %xor = xor i32 %x, %y
+  %xor0 = icmp eq i32 %xor, 0
+  %or = or i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %xor0, i32 %and, i32 %or
+  ret i32 %cond
+}
+; X^Y==0 ? X|Y : X&Y  -> X|Y
+define i32 @src_select_xor0_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor0_or_and(
+; CHECK-NEXT:   [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[AND:%.*]]
+  %xor = xor i32 %x, %y
+  %xor0 = icmp eq i32 %xor, 0
+  %or = or i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %xor0, i32 %or, i32 %and
+  ret i32 %cond
+}
+; X^Y!=0 ? X&Y : X|Y  -> X&Y
+define i32 @src_select_xor1_and_or(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor1_and_or(
+; CHECK-NEXT:   [[AND:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[AND:%.*]]
+  %xor = xor i32 %x, %y
+  %xor1 = icmp ne i32 %xor, 0
+  %or = or i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %xor1, i32 %and, i32 %or
+  ret i32 %cond
+}
+; X^Y!=0 ? X|Y : X&Y  -> X|Y
+define i32 @src_select_xor1_or_and(i32 %x, i32 %y) {
+; CHECK-LABEL: @src_select_xor1_or_and(
+; CHECK-NEXT:   [[OR:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT:   ret i32 [[OR:%.*]]
+  %xor = xor i32 %x, %y
+  %xor1 = icmp ne i32 %xor, 0
+  %or = or i32 %x, %y
+  %and = and i32 %x, %y
+  %cond = select i1 %xor1, i32 %or, i32 %and
+  ret i32 %cond
+}

>From c06c9015522496d5ca9258b8a3dbf8ca0312eb77 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 24 Nov 2023 06:37:57 +0900
Subject: [PATCH 2/2] [InstSimplify] Simplify select if it combinated
 `and/or/xor`

- (X & Y) == 0 ? X | Y : X ^ Y   --> X ^ Y
- (X & Y) != 0 ? X | Y : X ^ Y   --> X | Y
- (X | Y) == 0 ? X & Y : X ^ Y   --> X ^ Y
- (X | Y) != 0 ? X & Y : X ^ Y   --> X & Y
- (X ^ Y) == 0 ? X | Y : X & Y   --> X & Y
- (X ^ Y) != 0 ? X | Y : X & Y   --> X | Y

certain combinations of bitwise operators can be simplified to
returning the value of the True or False clause.

Proofs : https://alive2.llvm.org/ce/z/9jidcw

Fixed llvm#71792.
---
 llvm/lib/Analysis/InstructionSimplify.cpp | 57 +++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 7ef2ffd23b95e76..17bd291af4033dd 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4425,6 +4425,60 @@ Value *llvm::simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
                                   RecursionLimit);
 }
 
+/// Try simplifying the selection command when condition, trueValue, and
+/// falseValue are combinations of special bitwise operators.
+static Value *simplifySelectBitTestSpec(Value *CmpLHS, Value *CmpRHS,
+                                        Value *TrueVal, Value *FalseVal) {
+  Value *X, *Y;
+  // (X & Y) == 0 ? X | Y : X ^ Y   --> X ^ Y
+  // (X & Y) == 0 ? X ^ Y : X | Y   --> X | Y
+  // (X & Y) != 0 ? X | Y : X ^ Y   --> X | Y
+  // (X & Y) != 0 ? X ^ Y : X | Y   --> X ^ Y
+  if (match(CmpLHS, m_c_And(m_Value(X), m_Value(Y))) &&
+      match(CmpRHS, m_Zero())) {
+    if (match(TrueVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
+        match(FalseVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+      return FalseVal;
+    } else if (match(FalseVal, m_c_Or(m_Specific(X), m_Specific(Y))) &&
+               match(TrueVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+      return FalseVal;
+    }
+  }
+  // (X | Y) == 0 ? X & Y : X ^ Y   --> X ^ Y
+  // (X | Y) == 0 ? X ^ Y : X & Y   --> X & Y
+  // (X | Y) != 0 ? X & Y : X ^ Y   --> X & Y
+  // (X | Y) != 0 ? X ^ Y : X & Y   --> X ^ Y
+  if (match(CmpLHS, m_c_Or(m_Value(X), m_Value(Y))) &&
+      match(CmpRHS, m_Zero())) {
+    if (match(TrueVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+        match(FalseVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+      return FalseVal;
+    } else if (match(FalseVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+               match(TrueVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
+      return FalseVal;
+    }
+  }
+  // (X ^ Y) == 0 ? X | Y : X & Y   --> X & Y
+  // (X ^ Y) == 0 ? X & Y : X | Y   --> X | Y
+  // (X ^ Y) != 0 ? X | Y : X & Y   --> X | Y
+  // (X ^ Y) != 0 ? X & Y : X | Y   --> X & Y
+  // (X ^ Y) == 0 could be transformed to X == Y
+  // (X ^ Y) != 0 could be transformed to X != Y
+  if (match(CmpLHS, m_CombineOr(m_c_Xor(m_Value(X), m_Value(Y)), m_Value(X)))) {
+    if (Y && match(CmpRHS, m_Zero()) || match(CmpRHS, m_Value(Y))) {
+      if (match(TrueVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+          match(FalseVal, m_c_Or(m_Specific(X), m_Specific(Y)))) {
+        return FalseVal;
+      } else if (match(FalseVal, m_c_And(m_Specific(X), m_Specific(Y))) &&
+                 match(TrueVal, m_c_Or(m_Specific(X), m_Specific(Y)))) {
+        return FalseVal;
+      }
+    }
+  }
+
+  return nullptr;
+}
+
 /// Try to simplify a select instruction when its condition operand is an
 /// integer comparison where one operand of the compare is a constant.
 static Value *simplifySelectBitTest(Value *TrueVal, Value *FalseVal, Value *X,
@@ -4601,6 +4655,9 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
     }
   }
 
+  if (Value *V = simplifySelectBitTestSpec(CmpLHS, CmpRHS, TrueVal, FalseVal))
+    return V;
+
   if (Pred == ICmpInst::ICMP_EQ && match(CmpRHS, m_Zero())) {
     Value *X;
     const APInt *Y;



More information about the llvm-commits mailing list