[InstCombine] `sinkNotIntoOtherHandOfLogicalOp()`: allow extra invertible uses of...
authorRoman Lebedev <lebedev.ri@gmail.com>
Mon, 19 Dec 2022 01:21:51 +0000 (04:21 +0300)
committerRoman Lebedev <lebedev.ri@gmail.com>
Mon, 19 Dec 2022 02:00:58 +0000 (05:00 +0300)
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-and.ll
llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-logical-and.ll
llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-logical-or.ll
llvm/test/Transforms/InstCombine/sink-not-into-another-hand-of-or.ll

index f7fda4b..5bbeb42 100644 (file)
@@ -3675,11 +3675,13 @@ bool InstCombinerImpl::sinkNotIntoOtherHandOfLogicalOp(Instruction &I) {
   Value *NotOp1 = nullptr;
   Value **OpToInvert = nullptr;
   if (match(Op0, m_Not(m_Value(NotOp0))) &&
-      InstCombiner::isFreeToInvert(Op1, Op1->hasOneUse())) {
+      InstCombiner::isFreeToInvert(Op1, /*WillInvertAllUses=*/true) &&
+      InstCombiner::canFreelyInvertAllUsersOf(Op1, /*IgnoredUser=*/&I)) {
     Op0 = NotOp0;
     OpToInvert = &Op1;
   } else if (match(Op1, m_Not(m_Value(NotOp1))) &&
-             InstCombiner::isFreeToInvert(Op0, Op0->hasOneUse())) {
+             InstCombiner::isFreeToInvert(Op0, /*WillInvertAllUses=*/true) &&
+             InstCombiner::canFreelyInvertAllUsersOf(Op0, /*IgnoredUser=*/&I)) {
     Op1 = NotOp1;
     OpToInvert = &Op0;
   } else
@@ -3689,8 +3691,16 @@ bool InstCombinerImpl::sinkNotIntoOtherHandOfLogicalOp(Instruction &I) {
   if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr))
     return false;
 
-  *OpToInvert =
+  Builder.SetInsertPoint(
+      &*cast<Instruction>(*OpToInvert)->getInsertionPointAfterDef());
+  Value *NotOpToInvert =
       Builder.CreateNot(*OpToInvert, (*OpToInvert)->getName() + ".not");
+  (*OpToInvert)->replaceUsesWithIf(NotOpToInvert, [NotOpToInvert](Use &U) {
+    return U.getUser() != NotOpToInvert;
+  });
+  freelyInvertAllUsersOf(NotOpToInvert, /*IgnoredUser=*/&I);
+  *OpToInvert = NotOpToInvert;
+
   Value *NewBinOp;
   if (IsBinaryOp)
     NewBinOp = Builder.CreateBinOp(NewOpc, Op0, Op1, I.getName() + ".not");
index 090e832..71537cd 100644 (file)
@@ -28,8 +28,8 @@ define i8 @t1(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t1(
 ; CHECK-NEXT:    [[I0:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I3_NOT:%.*]] = or i1 [[I1]], [[I0]]
+; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I4]]
 ;
@@ -77,12 +77,11 @@ define i8 @n3(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
 ; Extra uses are invertible
 define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = or i1 [[I1]], [[I0:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = and i1 [[I1]], [[I3]]
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
@@ -95,12 +94,11 @@ define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 }
 define i8 @t4_commutative(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4_commutative(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = or i1 [[I1]], [[I0:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = and i1 [[I1]], [[I3]]
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
index 9fea168..0866fc2 100644 (file)
@@ -41,8 +41,8 @@ define i8 @t1(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t1(
 ; CHECK-NEXT:    [[I0:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I0]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I4]]
 ;
@@ -58,8 +58,8 @@ define i8 @t1_commutative(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t1_commutative(
 ; CHECK-NEXT:    [[I0:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I1]], i1 true, i1 [[I0]]
+; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I4]]
 ;
@@ -107,12 +107,11 @@ define i8 @n3(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
 ; Extra uses are invertible
 define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = select i1 [[I0:%.*]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3]], i1 [[I1]], i1 false
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
@@ -125,12 +124,11 @@ define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 }
 define i8 @t4_commutative(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4_commutative(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = select i1 [[I1]], i1 true, i1 [[I0:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I1]], i1 [[I3]], i1 false
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
index d49b13a..b6c9d24 100644 (file)
@@ -41,8 +41,8 @@ define i8 @t1(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t1(
 ; CHECK-NEXT:    [[I0:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I0]], i1 [[I1]], i1 false
+; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I4]]
 ;
@@ -58,8 +58,8 @@ define i8 @t1_commutative(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t1_commutative(
 ; CHECK-NEXT:    [[I0:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I1]], i1 [[I0]], i1 false
+; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I4]]
 ;
@@ -107,12 +107,11 @@ define i8 @n3(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
 ; Extra uses are invertible
 define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = select i1 [[I0:%.*]], i1 [[I1]], i1 false
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3]], i1 true, i1 [[I1]]
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
@@ -125,12 +124,11 @@ define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 }
 define i8 @t4_commutative(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4_commutative(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = select i1 [[I1]], i1 [[I0:%.*]], i1 false
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I1]], i1 true, i1 [[I3]]
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
index ce7f4b5..6777720 100644 (file)
@@ -28,8 +28,8 @@ define i8 @t1(i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t1(
 ; CHECK-NEXT:    [[I0:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I3_NOT:%.*]] = and i1 [[I1]], [[I0]]
+; CHECK-NEXT:    call void @use1(i1 [[I0]])
 ; CHECK-NEXT:    [[I4:%.*]] = select i1 [[I3_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I4]]
 ;
@@ -77,12 +77,11 @@ define i8 @n3(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3) {
 ; Extra uses are invertible
 define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = and i1 [[I1]], [[I0:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = or i1 [[I1]], [[I3]]
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use
@@ -95,12 +94,11 @@ define i8 @t4(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 }
 define i8 @t4_commutative(i1 %i0, i8 %v0, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) {
 ; CHECK-LABEL: @t4_commutative(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i8 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V2:%.*]], i8 [[V3:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i8 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I4_NOT:%.*]] = and i1 [[I1]], [[I0:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = select i1 [[I1]], i8 [[V3:%.*]], i8 [[V2:%.*]]
 ; CHECK-NEXT:    call void @use8(i8 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = xor i1 [[I0:%.*]], true
-; CHECK-NEXT:    [[I4:%.*]] = or i1 [[I1]], [[I3]]
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4]], i8 [[V4:%.*]], i8 [[V5:%.*]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I4_NOT]], i8 [[V5:%.*]], i8 [[V4:%.*]]
 ; CHECK-NEXT:    ret i8 [[I5]]
 ;
   %i1 = icmp eq i8 %v0, %v1 ; has extra invertible use