[llvm] e36d351 - [InstSimplify] (x | y) & (x | !y) --> x

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 6 09:33:08 PDT 2021


Author: Sanjay Patel
Date: 2021-10-06T12:31:25-04:00
New Revision: e36d351d19b1365275c7d5f2bf4e6ac17a42ad2c

URL: https://github.com/llvm/llvm-project/commit/e36d351d19b1365275c7d5f2bf4e6ac17a42ad2c
DIFF: https://github.com/llvm/llvm-project/commit/e36d351d19b1365275c7d5f2bf4e6ac17a42ad2c.diff

LOG: [InstSimplify] (x | y) & (x | !y) --> x

https://alive2.llvm.org/ce/z/QagQMn

This fold is handled by instcombine via SimplifyUsingDistributiveLaws(),
but we are missing the sibliing fold for 'logical and' (implemented with
'select'). Retrofitting the code in instcombine looks much harder
than just adding a small adjustment here, and this is potentially more
efficient and beneficial to other passes.

Added: 
    

Modified: 
    llvm/lib/Analysis/InstructionSimplify.cpp
    llvm/test/Transforms/InstSimplify/and.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 4dace886fef9..556250e527b0 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2042,11 +2042,19 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
   if (match(Op1, m_c_Or(m_Specific(Op0), m_Value())))
     return Op0;
 
+  // (X | Y) & (X | ~Y) --> X (commuted 8 ways)
+  Value *X, *Y;
+  if (match(Op0, m_c_Or(m_Value(X), m_Not(m_Value(Y)))) &&
+      match(Op1, m_c_Or(m_Deferred(X), m_Deferred(Y))))
+    return X;
+  if (match(Op1, m_c_Or(m_Value(X), m_Not(m_Value(Y)))) &&
+      match(Op0, m_c_Or(m_Deferred(X), m_Deferred(Y))))
+    return X;
+
   if (Value *V = simplifyLogicOfAddSub(Op0, Op1, Instruction::And))
     return V;
 
   // A mask that only clears known zeros of a shifted value is a no-op.
-  Value *X;
   const APInt *Mask;
   const APInt *ShAmt;
   if (match(Op1, m_APInt(Mask))) {
@@ -2143,7 +2151,7 @@ static Value *SimplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
   //     if Mask = ((1 << effective_width_of(X)) - 1) << A
   // SimplifyDemandedBits in InstCombine can optimize the general case.
   // This pattern aims to help other passes for a common case.
-  Value *Y, *XShifted;
+  Value *XShifted;
   if (match(Op1, m_APInt(Mask)) &&
       match(Op0, m_c_Or(m_CombineAnd(m_NUWShl(m_Value(X), m_APInt(ShAmt)),
                                      m_Value(XShifted)),

diff  --git a/llvm/test/Transforms/InstSimplify/and.ll b/llvm/test/Transforms/InstSimplify/and.ll
index 4b47f398c129..0ed61c59dda4 100644
--- a/llvm/test/Transforms/InstSimplify/and.ll
+++ b/llvm/test/Transforms/InstSimplify/and.ll
@@ -9,13 +9,11 @@ define i32 @poison(i32 %x) {
   ret i32 %v
 }
 
+; (X | Y) & (X | ~Y) --> X (commuted 8 ways)
+
 define i8 @or_or_not_commute0(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_or_not_commute0(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[XORY:%.*]] = or i8 [[X:%.*]], [[Y]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORY]], [[XORYNOT]]
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %ynot = xor i8 %y, -1
   %xory = or i8 %x, %y
@@ -26,11 +24,7 @@ define i8 @or_or_not_commute0(i8 %x, i8 %y) {
 
 define <2 x i5> @or_or_not_commute1(<2 x i5> %x, <2 x i5> %y) {
 ; CHECK-LABEL: @or_or_not_commute1(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor <2 x i5> [[Y:%.*]], <i5 -1, i5 -1>
-; CHECK-NEXT:    [[XORY:%.*]] = or <2 x i5> [[X:%.*]], [[Y]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or <2 x i5> [[X]], [[YNOT]]
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i5> [[XORYNOT]], [[XORY]]
-; CHECK-NEXT:    ret <2 x i5> [[AND]]
+; CHECK-NEXT:    ret <2 x i5> [[X:%.*]]
 ;
   %ynot = xor <2 x i5> %y, <i5 -1, i5 -1>
   %xory = or <2 x i5> %x, %y
@@ -41,11 +35,7 @@ define <2 x i5> @or_or_not_commute1(<2 x i5> %x, <2 x i5> %y) {
 
 define <2 x i8> @or_or_not_commute2(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @or_or_not_commute2(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor <2 x i8> [[Y:%.*]], <i8 poison, i8 -1>
-; CHECK-NEXT:    [[XORY:%.*]] = or <2 x i8> [[X:%.*]], [[Y]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or <2 x i8> [[YNOT]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i8> [[XORY]], [[XORYNOT]]
-; CHECK-NEXT:    ret <2 x i8> [[AND]]
+; CHECK-NEXT:    ret <2 x i8> [[X:%.*]]
 ;
   %ynot = xor <2 x i8> %y, <i8 poison, i8 -1>
   %xory = or <2 x i8> %x, %y
@@ -56,11 +46,7 @@ define <2 x i8> @or_or_not_commute2(<2 x i8> %x, <2 x i8> %y) {
 
 define i8 @or_or_not_commute3(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_or_not_commute3(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[XORY:%.*]] = or i8 [[X:%.*]], [[Y]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[YNOT]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORYNOT]], [[XORY]]
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %ynot = xor i8 %y, -1
   %xory = or i8 %x, %y
@@ -70,11 +56,7 @@ define i8 @or_or_not_commute3(i8 %x, i8 %y) {
 }
 define i8 @or_or_not_commute4(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_or_not_commute4(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORY]], [[XORYNOT]]
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %ynot = xor i8 %y, -1
   %xory = or i8 %y, %x
@@ -85,11 +67,7 @@ define i8 @or_or_not_commute4(i8 %x, i8 %y) {
 
 define i8 @or_or_not_commute5(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_or_not_commute5(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORYNOT]], [[XORY]]
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %ynot = xor i8 %y, -1
   %xory = or i8 %y, %x
@@ -100,11 +78,7 @@ define i8 @or_or_not_commute5(i8 %x, i8 %y) {
 
 define i8 @or_or_not_commute6(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_or_not_commute6(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[YNOT]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORY]], [[XORYNOT]]
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %ynot = xor i8 %y, -1
   %xory = or i8 %y, %x
@@ -115,11 +89,7 @@ define i8 @or_or_not_commute6(i8 %x, i8 %y) {
 
 define i8 @or_or_not_commute7(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_or_not_commute7(
-; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[XORY:%.*]] = or i8 [[Y]], [[X:%.*]]
-; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[YNOT]], [[X]]
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORYNOT]], [[XORY]]
-; CHECK-NEXT:    ret i8 [[AND]]
+; CHECK-NEXT:    ret i8 [[X:%.*]]
 ;
   %ynot = xor i8 %y, -1
   %xory = or i8 %y, %x
@@ -127,3 +97,37 @@ define i8 @or_or_not_commute7(i8 %x, i8 %y) {
   %and = and i8 %xorynot, %xory
   ret i8 %and
 }
+
+; negative test - wrong logic op
+
+define i8 @or_xor_not(i8 %x, i8 %y) {
+; CHECK-LABEL: @or_xor_not(
+; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[XXORY:%.*]] = xor i8 [[Y]], [[X:%.*]]
+; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORYNOT]], [[XXORY]]
+; CHECK-NEXT:    ret i8 [[AND]]
+;
+  %ynot = xor i8 %y, -1
+  %xxory = xor i8 %y, %x
+  %xorynot = or i8 %x, %ynot
+  %and = and i8 %xorynot, %xxory
+  ret i8 %and
+}
+
+; negative test - must have common operands
+
+define i8 @or_or_not_no_common_op(i8 %x, i8 %y, i8 %z) {
+; CHECK-LABEL: @or_or_not_no_common_op(
+; CHECK-NEXT:    [[XORZ:%.*]] = or i8 [[Z:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[YNOT:%.*]] = xor i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[XORYNOT:%.*]] = or i8 [[X]], [[YNOT]]
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[XORYNOT]], [[XORZ]]
+; CHECK-NEXT:    ret i8 [[AND]]
+;
+  %xorz = or i8 %z, %x
+  %ynot = xor i8 %y, -1
+  %xorynot = or i8 %x, %ynot
+  %and = and i8 %xorynot, %xorz
+  ret i8 %and
+}


        


More information about the llvm-commits mailing list