[llvm] bc72baa - [InstCombine] add folds for logical nand/nor

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 5 15:37:50 PDT 2021


Author: Sanjay Patel
Date: 2021-10-05T18:31:20-04:00
New Revision: bc72baa04789d337bca0261d4a13a3851e11c5be

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

LOG: [InstCombine] add folds for logical nand/nor

This is noted as a regression in:
https://llvm.org/PR52077

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/not.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 293825ddfc92..88ad6907b98b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3276,22 +3276,35 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
   // Apply DeMorgan's Law for 'nand' / 'nor' logic with an inverted operand.
   // We must eliminate the and/or (one-use) for these transforms to not increase
   // the instruction count.
+  //
   // ~(~X & Y) --> (X | ~Y)
   // ~(Y & ~X) --> (X | ~Y)
+  //
+  // Note: The logical matches do not check for the commuted patterns because
+  //       those are handled via SimplifySelectsFeedingBinaryOp().
+  Type *Ty = I.getType();
   Value *X, *Y;
   if (match(NotOp, m_OneUse(m_c_And(m_Not(m_Value(X)), m_Value(Y))))) {
     Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
     return BinaryOperator::CreateOr(X, NotY);
   }
+  if (match(NotOp, m_OneUse(m_LogicalAnd(m_Not(m_Value(X)), m_Value(Y))))) {
+    Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
+    return SelectInst::Create(X, ConstantInt::getTrue(Ty), NotY);
+  }
+
   // ~(~X | Y) --> (X & ~Y)
   // ~(Y | ~X) --> (X & ~Y)
   if (match(NotOp, m_OneUse(m_c_Or(m_Not(m_Value(X)), m_Value(Y))))) {
     Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
     return BinaryOperator::CreateAnd(X, NotY);
   }
+  if (match(NotOp, m_OneUse(m_LogicalOr(m_Not(m_Value(X)), m_Value(Y))))) {
+    Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
+    return SelectInst::Create(X, NotY, ConstantInt::getFalse(Ty));
+  }
 
   // Is this a 'not' (~) fed by a binary operator?
-  Type *Ty = I.getType();
   BinaryOperator *NotVal;
   if (match(NotOp, m_BinOp(NotVal))) {
     if (NotVal->getOpcode() == Instruction::And ||

diff  --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll
index 21f6507bdba5..6a5b4bbd9f14 100644
--- a/llvm/test/Transforms/InstCombine/not.ll
+++ b/llvm/test/Transforms/InstCombine/not.ll
@@ -481,9 +481,8 @@ define i1 @not_select_bool(i1 %x, i1 %y, i1 %z) {
 
 define i1 @not_select_bool_const1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_select_bool_const1(
-; CHECK-NEXT:    [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[NOT_X]], i1 true, i1 [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[SEL]], true
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor i1 [[Y:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 [[Y_NOT]], i1 false
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %sel = select i1 %x, i1 %y, i1 true
@@ -515,9 +514,8 @@ define i1 @not_select_bool_const3(i1 %x, i1 %y) {
 
 define i1 @not_select_bool_const4(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_select_bool_const4(
-; CHECK-NEXT:    [[NOT_X:%.*]] = xor i1 [[X:%.*]], true
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[NOT_X]], i1 [[Y:%.*]], i1 false
-; CHECK-NEXT:    [[R:%.*]] = xor i1 [[SEL]], true
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor i1 [[Y:%.*]], true
+; CHECK-NEXT:    [[R:%.*]] = select i1 [[X:%.*]], i1 true, i1 [[Y_NOT]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %sel = select i1 %x, i1 false, i1 %y
@@ -527,9 +525,8 @@ define i1 @not_select_bool_const4(i1 %x, i1 %y) {
 
 define <2 x i1> @not_logicalAnd_not_op0(<2 x i1> %x, <2 x i1> %y) {
 ; CHECK-LABEL: @not_logicalAnd_not_op0(
-; CHECK-NEXT:    [[NOTX:%.*]] = xor <2 x i1> [[X:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[AND:%.*]] = select <2 x i1> [[NOTX]], <2 x i1> [[Y:%.*]], <2 x i1> zeroinitializer
-; CHECK-NEXT:    [[NOTAND:%.*]] = xor <2 x i1> [[AND]], <i1 true, i1 true>
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor <2 x i1> [[Y:%.*]], <i1 true, i1 true>
+; CHECK-NEXT:    [[NOTAND:%.*]] = select <2 x i1> [[X:%.*]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[Y_NOT]]
 ; CHECK-NEXT:    ret <2 x i1> [[NOTAND]]
 ;
   %notx = xor <2 x i1> %x, <i1 true, i1 true>
@@ -554,8 +551,8 @@ define i1 @not_logicalAnd_not_op0_use1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_logicalAnd_not_op0_use1(
 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
 ; CHECK-NEXT:    call void @use1(i1 [[NOTX]])
-; CHECK-NEXT:    [[AND:%.*]] = select i1 [[NOTX]], i1 [[Y:%.*]], i1 false
-; CHECK-NEXT:    [[NOTAND:%.*]] = xor i1 [[AND]], true
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor i1 [[Y:%.*]], true
+; CHECK-NEXT:    [[NOTAND:%.*]] = select i1 [[X]], i1 true, i1 [[Y_NOT]]
 ; CHECK-NEXT:    ret i1 [[NOTAND]]
 ;
   %notx = xor i1 %x, true
@@ -565,6 +562,8 @@ define i1 @not_logicalAnd_not_op0_use1(i1 %x, i1 %y) {
   ret i1 %notand
 }
 
+; negative test
+
 define i1 @not_logicalAnd_not_op0_use2(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_logicalAnd_not_op0_use2(
 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
@@ -582,9 +581,8 @@ define i1 @not_logicalAnd_not_op0_use2(i1 %x, i1 %y) {
 
 define <2 x i1> @not_logicalOr_not_op0(<2 x i1> %x, <2 x i1> %y) {
 ; CHECK-LABEL: @not_logicalOr_not_op0(
-; CHECK-NEXT:    [[NOTX:%.*]] = xor <2 x i1> [[X:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[OR:%.*]] = select <2 x i1> [[NOTX]], <2 x i1> <i1 true, i1 true>, <2 x i1> [[Y:%.*]]
-; CHECK-NEXT:    [[NOTOR:%.*]] = xor <2 x i1> [[OR]], <i1 true, i1 true>
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor <2 x i1> [[Y:%.*]], <i1 true, i1 true>
+; CHECK-NEXT:    [[NOTOR:%.*]] = select <2 x i1> [[X:%.*]], <2 x i1> [[Y_NOT]], <2 x i1> zeroinitializer
 ; CHECK-NEXT:    ret <2 x i1> [[NOTOR]]
 ;
   %notx = xor <2 x i1> %x, <i1 true, i1 true>
@@ -609,8 +607,8 @@ define i1 @not_logicalOr_not_op0_use1(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_logicalOr_not_op0_use1(
 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true
 ; CHECK-NEXT:    call void @use1(i1 [[NOTX]])
-; CHECK-NEXT:    [[OR:%.*]] = select i1 [[NOTX]], i1 true, i1 [[Y:%.*]]
-; CHECK-NEXT:    [[NOTOR:%.*]] = xor i1 [[OR]], true
+; CHECK-NEXT:    [[Y_NOT:%.*]] = xor i1 [[Y:%.*]], true
+; CHECK-NEXT:    [[NOTOR:%.*]] = select i1 [[X]], i1 [[Y_NOT]], i1 false
 ; CHECK-NEXT:    ret i1 [[NOTOR]]
 ;
   %notx = xor i1 %x, true
@@ -620,6 +618,8 @@ define i1 @not_logicalOr_not_op0_use1(i1 %x, i1 %y) {
   ret i1 %notor
 }
 
+; negative test
+
 define i1 @not_logicalOr_not_op0_use2(i1 %x, i1 %y) {
 ; CHECK-LABEL: @not_logicalOr_not_op0_use2(
 ; CHECK-NEXT:    [[NOTX:%.*]] = xor i1 [[X:%.*]], true


        


More information about the llvm-commits mailing list