[llvm-branch-commits] [llvm] 79b0d21 - [InstCombine] Fold `(~x) & y` --> `~(x | (~y))` iff it is free to do so
Roman Lebedev via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jan 22 06:29:45 PST 2021
Author: Roman Lebedev
Date: 2021-01-22T17:23:54+03:00
New Revision: 79b0d21ce92f1a5ff4c822d1a5c664196b338535
URL: https://github.com/llvm/llvm-project/commit/79b0d21ce92f1a5ff4c822d1a5c664196b338535
DIFF: https://github.com/llvm/llvm-project/commit/79b0d21ce92f1a5ff4c822d1a5c664196b338535.diff
LOG: [InstCombine] Fold `(~x) & y` --> `~(x | (~y))` iff it is free to do so
Iff we know we can get rid of the inversions in the new pattern,
we can thus get rid of the inversion in the old pattern,
this decreasing instruction count.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-and.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index c42f113feca3..944e7c4b1325 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -1983,6 +1983,10 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
return SelectInst::Create(NewICmpInst, X, ConstantInt::getNullValue(Ty));
}
+ // (~x) & y --> ~(x | (~y)) iff that gets rid of inversions
+ if (sinkNotIntoOtherHandOfAnd(I))
+ return &I;
+
return nullptr;
}
@@ -3089,6 +3093,45 @@ static Instruction *sinkNotIntoXor(BinaryOperator &I,
return BinaryOperator::CreateXor(NotX, Y, I.getName() + ".demorgan");
}
+// Transform
+// z = (~x) & y
+// into:
+// z = ~(x | (~y))
+// iff y is free to invert and all uses of z can be freely updated.
+bool InstCombinerImpl::sinkNotIntoOtherHandOfAnd(BinaryOperator &I) {
+ Instruction::BinaryOps NewOpc;
+ switch (I.getOpcode()) {
+ case Instruction::And:
+ NewOpc = Instruction::Or;
+ break;
+ default:
+ return false;
+ };
+
+ Value *X, *Y;
+ if (!match(&I, m_c_BinOp(m_Not(m_Value(X)), m_Value(Y))))
+ return false;
+
+ // Will we be able to fold the `not` into Y eventually?
+ if (!InstCombiner::isFreeToInvert(Y, Y->hasOneUse()))
+ return false;
+
+ // And can our users be adapted?
+ if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr))
+ return false;
+
+ Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not");
+ Value *NewBinOp =
+ BinaryOperator::Create(NewOpc, X, NotY, I.getName() + ".not");
+ Builder.Insert(NewBinOp);
+ replaceInstUsesWith(I, NewBinOp);
+ // We can not just create an outer `not`, it will most likely be immediately
+ // folded back, reconstructing our initial pattern, and causing an
+ // infinite combine loop, so immediately manually fold it away.
+ freelyInvertAllUsersOf(NewBinOp);
+ return true;
+}
+
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
// here. We should standardize that construct where it is needed or choose some
// other way to ensure that commutated variants of patterns are not missed.
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 16bc26520c18..c56b31bd227b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -105,6 +105,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Value *simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, bool Inverted);
Instruction *visitAnd(BinaryOperator &I);
Instruction *visitOr(BinaryOperator &I);
+ bool sinkNotIntoOtherHandOfAnd(BinaryOperator &I);
Instruction *visitXor(BinaryOperator &I);
Instruction *visitShl(BinaryOperator &I);
Value *reassociateShiftAmtsOfTwoSameDirectionShifts(
diff --git a/llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-and.ll b/llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-and.ll
index 14c889b23e39..17c37c836bb3 100644
--- a/llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-and.ll
+++ b/llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-and.ll
@@ -12,10 +12,9 @@ declare void @use1(i1)
; Most basic positive test
define i32 @t0(i1 %i0, i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
; CHECK-LABEL: @t0(
-; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[I2:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT: [[I3:%.*]] = and i1 [[I1]], [[I2]]
-; CHECK-NEXT: [[I4:%.*]] = select i1 [[I3]], i32 [[V2:%.*]], i32 [[V3:%.*]]
+; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[I1]], [[I0:%.*]]
+; CHECK-NEXT: [[I4:%.*]] = select i1 [[TMP1]], i32 [[V3:%.*]], i32 [[V2:%.*]]
; CHECK-NEXT: ret i32 [[I4]]
;
%i1 = icmp eq i32 %v0, %v1
@@ -27,11 +26,10 @@ define i32 @t0(i1 %i0, i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
define i32 @t1(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i32 %v4, i32 %v5) {
; CHECK-LABEL: @t1(
; CHECK-NEXT: [[I0:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT: [[I1:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT: [[I1:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
; CHECK-NEXT: call void @use1(i1 [[I0]])
-; CHECK-NEXT: [[I2:%.*]] = xor i1 [[I0]], true
-; CHECK-NEXT: [[I3:%.*]] = and i1 [[I1]], [[I2]]
-; CHECK-NEXT: [[I4:%.*]] = select i1 [[I3]], i32 [[V4:%.*]], i32 [[V5:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i1 [[I0]], [[I1]]
+; CHECK-NEXT: [[I4:%.*]] = select i1 [[TMP1]], i32 [[V5:%.*]], i32 [[V4:%.*]]
; CHECK-NEXT: ret i32 [[I4]]
;
%i0 = icmp eq i32 %v0, %v1
More information about the llvm-branch-commits
mailing list