[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