[llvm] b20cccc - [InstCombine] Support sinking `not` into logical operand with invertible hands

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 18 17:11:41 PST 2022


Author: Roman Lebedev
Date: 2022-12-19T04:11:16+03:00
New Revision: b20ccccda22b1465b54bd069bd53a0a96224f3ec

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

LOG: [InstCombine] Support sinking `not` into logical operand with invertible hands

The important bit here is that we gracefully handle other uses,
iff they can be adapted to inversion.

I'll note, the previous logic was actively bad,
it increased instruction count since it didn't actually ensure
that the inversions happened.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/lib/Transforms/InstCombine/InstCombineInternal.h
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
    llvm/test/Transforms/InstCombine/sink-not-into-and.ll
    llvm/test/Transforms/InstCombine/sink-not-into-logical-and.ll
    llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll
    llvm/test/Transforms/InstCombine/sink-not-into-or.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 90ed6bc368c61..f7fda4b9aa415 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3609,6 +3609,55 @@ static Instruction *canonicalizeAbs(BinaryOperator &Xor,
   return nullptr;
 }
 
+// Transform
+//   z = ~(x &/| y)
+// into:
+//   z = ((~x) |/& (~y))
+// iff both x and y are free to invert and all uses of z can be freely updated.
+bool InstCombinerImpl::sinkNotIntoLogicalOp(Instruction &I) {
+  Value *Op0, *Op1;
+  if (!match(&I, m_LogicalOp(m_Value(Op0), m_Value(Op1))))
+    return false;
+  Instruction::BinaryOps NewOpc =
+      match(&I, m_LogicalAnd()) ? Instruction::Or : Instruction::And;
+  bool IsBinaryOp = isa<BinaryOperator>(I);
+
+  // Can our users be adapted?
+  if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr))
+    return false;
+
+  // And can the operands be adapted?
+  for (Value *Op : {Op0, Op1})
+    if (!InstCombiner::isFreeToInvert(Op, /*WillInvertAllUses=*/true) ||
+        !InstCombiner::canFreelyInvertAllUsersOf(Op, /*IgnoredUser=*/&I))
+      return false;
+
+  for (Value **Op : {&Op0, &Op1}) {
+    Builder.SetInsertPoint(
+        &*cast<Instruction>(*Op)->getInsertionPointAfterDef());
+    Value *NotOp = Builder.CreateNot(*Op, (*Op)->getName() + ".not");
+    (*Op)->replaceUsesWithIf(NotOp,
+                             [NotOp](Use &U) { return U.getUser() != NotOp; });
+    freelyInvertAllUsersOf(NotOp, /*IgnoredUser=*/&I);
+    *Op = NotOp;
+  }
+
+  Builder.SetInsertPoint(I.getInsertionPointAfterDef());
+  Value *NewLogicOp;
+  if (IsBinaryOp)
+    NewLogicOp = Builder.CreateBinOp(NewOpc, Op0, Op1, I.getName() + ".not");
+  else
+    NewLogicOp =
+        Builder.CreateLogicalOp(NewOpc, Op0, Op1, I.getName() + ".not");
+
+  replaceInstUsesWith(I, NewLogicOp);
+  // 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(NewLogicOp);
+  return true;
+}
+
 // Transform
 //   z = (~x) &/| y
 // into:
@@ -3694,23 +3743,6 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
   // Is this a 'not' (~) fed by a binary operator?
   BinaryOperator *NotVal;
   if (match(NotOp, m_BinOp(NotVal))) {
-    if (NotVal->getOpcode() == Instruction::And ||
-        NotVal->getOpcode() == Instruction::Or) {
-      // Apply DeMorgan's Law when inverts are free:
-      // ~(X & Y) --> (~X | ~Y)
-      // ~(X | Y) --> (~X & ~Y)
-      if (isFreeToInvert(NotVal->getOperand(0),
-                         NotVal->getOperand(0)->hasOneUse()) &&
-          isFreeToInvert(NotVal->getOperand(1),
-                         NotVal->getOperand(1)->hasOneUse())) {
-        Value *NotX = Builder.CreateNot(NotVal->getOperand(0), "notlhs");
-        Value *NotY = Builder.CreateNot(NotVal->getOperand(1), "notrhs");
-        if (NotVal->getOpcode() == Instruction::And)
-          return BinaryOperator::CreateOr(NotX, NotY);
-        return BinaryOperator::CreateAnd(NotX, NotY);
-      }
-    }
-
     // ~((-X) | Y) --> (X - 1) & (~Y)
     if (match(NotVal,
               m_OneUse(m_c_Or(m_OneUse(m_Neg(m_Value(X))), m_Value(Y))))) {
@@ -3775,6 +3807,10 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
     return &I;
   }
 
+  if (auto *NotOpI = dyn_cast<Instruction>(NotOp))
+    if (sinkNotIntoLogicalOp(*NotOpI))
+      return &I;
+
   // Eliminate a bitwise 'not' op of 'not' min/max by inverting the min/max:
   // ~min(~X, ~Y) --> max(X, Y)
   // ~max(~X, Y) --> min(X, ~Y)

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 83623aacc5e42..f700cdb84d573 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -106,6 +106,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   Value *simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, bool Inverted);
   Instruction *visitAnd(BinaryOperator &I);
   Instruction *visitOr(BinaryOperator &I);
+  bool sinkNotIntoLogicalOp(Instruction &I);
   bool sinkNotIntoOtherHandOfLogicalOp(Instruction &I);
   Instruction *visitXor(BinaryOperator &I);
   Instruction *visitShl(BinaryOperator &I);
@@ -330,7 +331,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
   Instruction *matchSAddSubSat(IntrinsicInst &MinMax1);
   Instruction *foldNot(BinaryOperator &I);
 
-  void freelyInvertAllUsersOf(Value *V);
+  void freelyInvertAllUsersOf(Value *V, Value *IgnoredUser = nullptr);
 
   /// Determine if a pair of casts can be replaced by a single cast.
   ///

diff  --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 736b9aa8ec244..c6e49110113b9 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -947,8 +947,10 @@ Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I,
 
 /// Freely adapt every user of V as-if V was changed to !V.
 /// WARNING: only if canFreelyInvertAllUsersOf() said this can be done.
-void InstCombinerImpl::freelyInvertAllUsersOf(Value *I) {
-  for (User *U : I->users()) {
+void InstCombinerImpl::freelyInvertAllUsersOf(Value *I, Value *IgnoredUser) {
+  for (User *U : make_early_inc_range(I->users())) {
+    if (U == IgnoredUser)
+      continue; // Don't consider this user.
     switch (cast<Instruction>(U)->getOpcode()) {
     case Instruction::Select: {
       auto *SI = cast<SelectInst>(U);

diff  --git a/llvm/test/Transforms/InstCombine/sink-not-into-and.ll b/llvm/test/Transforms/InstCombine/sink-not-into-and.ll
index b77e09ca3a666..9db6440a49ee7 100644
--- a/llvm/test/Transforms/InstCombine/sink-not-into-and.ll
+++ b/llvm/test/Transforms/InstCombine/sink-not-into-and.ll
@@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t0(
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I4:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; Hands have invertible uses
 define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t7(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -133,13 +131,11 @@ define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 }
 define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t8(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I2_NOT:%.*]] = xor i1 [[I2]], true
-; CHECK-NEXT:    call void @use1(i1 [[I2_NOT]])
-; CHECK-NEXT:    [[I3:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I2]])
+; CHECK-NEXT:    [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -151,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 }
 define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t9(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I2_NOT:%.*]] = xor i1 [[I2]], true
-; CHECK-NEXT:    call void @use1(i1 [[I2_NOT]])
-; CHECK-NEXT:    [[I3:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I2]])
+; CHECK-NEXT:    [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -181,8 +174,7 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
 ; CHECK-NEXT:    [[I3:%.*]] = and i1 [[I2]], [[I1]]
 ; CHECK-NEXT:    call void @use1(i1 [[I3]])
-; CHECK-NEXT:    [[I4_DEMORGAN:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I4_DEMORGAN]], true
+; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
 ; CHECK-NEXT:    ret i1 [[I4]]
 ;
   %i1 = icmp eq i32 %v0, %v1
@@ -196,14 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; All other uses can be adapted.
 define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
 ; CHECK-LABEL: @t11(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4_DEMORGAN:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I4_DEMORGAN]], true
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = or i1 [[I2]], [[I1]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[I5]])
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3

diff  --git a/llvm/test/Transforms/InstCombine/sink-not-into-logical-and.ll b/llvm/test/Transforms/InstCombine/sink-not-into-logical-and.ll
index 496b9cdc0873b..f07840c8bbdc9 100644
--- a/llvm/test/Transforms/InstCombine/sink-not-into-logical-and.ll
+++ b/llvm/test/Transforms/InstCombine/sink-not-into-logical-and.ll
@@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t0(
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
-; CHECK-NEXT:    ret i1 [[I3]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; Hands have invertible uses
 define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t7(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -136,8 +134,8 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
-; CHECK-NEXT:    ret i1 [[I3]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -149,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 }
 define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t9(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I2_NOT:%.*]] = xor i1 [[I2]], true
-; CHECK-NEXT:    call void @use1(i1 [[I2_NOT]])
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I2]])
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -193,13 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; All other uses can be adapted.
 define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
 ; CHECK-LABEL: @t11(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[I5]])
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3

diff  --git a/llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll b/llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll
index 055e81c19bc8b..017e6972f78b3 100644
--- a/llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll
+++ b/llvm/test/Transforms/InstCombine/sink-not-into-logical-or.ll
@@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t0(
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
-; CHECK-NEXT:    ret i1 [[I3]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; Hands have invertible uses
 define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t7(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -136,8 +134,8 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[I2]])
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
-; CHECK-NEXT:    ret i1 [[I3]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -149,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 }
 define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t9(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I2_NOT:%.*]] = xor i1 [[I2]], true
-; CHECK-NEXT:    call void @use1(i1 [[I2_NOT]])
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I2]])
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -193,13 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; All other uses can be adapted.
 define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
 ; CHECK-LABEL: @t11(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = select i1 [[I2]], i1 true, i1 [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = select i1 [[I2]], i1 [[I1]], i1 false
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[I5]])
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3

diff  --git a/llvm/test/Transforms/InstCombine/sink-not-into-or.ll b/llvm/test/Transforms/InstCombine/sink-not-into-or.ll
index 1e32220dda120..0b758112f699e 100644
--- a/llvm/test/Transforms/InstCombine/sink-not-into-or.ll
+++ b/llvm/test/Transforms/InstCombine/sink-not-into-or.ll
@@ -14,8 +14,8 @@ define i1 @t0(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t0(
 ; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
 ; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I4:%.*]] = and i1 [[I2]], [[I1]]
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = and i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -115,13 +115,11 @@ define i1 @n6(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; Hands have invertible uses
 define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t7(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = and i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -133,13 +131,11 @@ define i1 @t7(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 }
 define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t8(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I2_NOT:%.*]] = xor i1 [[I2]], true
-; CHECK-NEXT:    call void @use1(i1 [[I2_NOT]])
-; CHECK-NEXT:    [[I3:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I2]])
+; CHECK-NEXT:    [[I3_NOT:%.*]] = and i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3
@@ -151,15 +147,12 @@ define i1 @t8(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 }
 define i1 @t9(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-LABEL: @t9(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I1_NOT:%.*]] = xor i1 [[I1]], true
-; CHECK-NEXT:    call void @use1(i1 [[I1_NOT]])
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I2_NOT:%.*]] = xor i1 [[I2]], true
-; CHECK-NEXT:    call void @use1(i1 [[I2_NOT]])
-; CHECK-NEXT:    [[I3:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I1]])
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    call void @use1(i1 [[I2]])
+; CHECK-NEXT:    [[I3_NOT:%.*]] = and i1 [[I2]], [[I1]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i1.not = xor i1 %i1, -1
@@ -181,8 +174,7 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
 ; CHECK-NEXT:    [[I3:%.*]] = or i1 [[I2]], [[I1]]
 ; CHECK-NEXT:    call void @use1(i1 [[I3]])
-; CHECK-NEXT:    [[I4_DEMORGAN:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I4_DEMORGAN]], true
+; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I3]], true
 ; CHECK-NEXT:    ret i1 [[I4]]
 ;
   %i1 = icmp eq i32 %v0, %v1
@@ -196,14 +188,12 @@ define i1 @n10(i32 %v0, i32 %v1, i32 %v2, i32 %v3) {
 ; All other uses can be adapted.
 define i1 @t11(i32 %v0, i32 %v1, i32 %v2, i32 %v3, i1 %v4, i1 %v5) {
 ; CHECK-LABEL: @t11(
-; CHECK-NEXT:    [[I1:%.*]] = icmp eq i32 [[V0:%.*]], [[V1:%.*]]
-; CHECK-NEXT:    [[I2:%.*]] = icmp eq i32 [[V2:%.*]], [[V3:%.*]]
-; CHECK-NEXT:    [[I3:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4_DEMORGAN:%.*]] = or i1 [[I2]], [[I1]]
-; CHECK-NEXT:    [[I4:%.*]] = xor i1 [[I4_DEMORGAN]], true
-; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3]], i1 [[V4:%.*]], i1 [[V5:%.*]]
+; CHECK-NEXT:    [[I1:%.*]] = icmp ne i32 [[V0:%.*]], [[V1:%.*]]
+; CHECK-NEXT:    [[I2:%.*]] = icmp ne i32 [[V2:%.*]], [[V3:%.*]]
+; CHECK-NEXT:    [[I3_NOT:%.*]] = and i1 [[I2]], [[I1]]
+; CHECK-NEXT:    [[I5:%.*]] = select i1 [[I3_NOT]], i1 [[V5:%.*]], i1 [[V4:%.*]]
 ; CHECK-NEXT:    call void @use1(i1 [[I5]])
-; CHECK-NEXT:    ret i1 [[I4]]
+; CHECK-NEXT:    ret i1 [[I3_NOT]]
 ;
   %i1 = icmp eq i32 %v0, %v1
   %i2 = icmp eq i32 %v2, %v3


        


More information about the llvm-commits mailing list