[llvm] c1cd698 - [InstSimplify] Simplify bool icmp with not in LHS

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 9 13:26:52 PST 2021


Author: Hasyimi Bahrudin
Date: 2021-12-09T16:26:46-05:00
New Revision: c1cd698a5228ef687641fdf34742dec80a08e085

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

LOG: [InstSimplify] Simplify bool icmp with not in LHS

Refer to https://llvm.org/PR52546.

Simplifies the following cases:
    not(X) == 0 -> X != 0 -> X
    not(X) <=u 0 -> X >u 0 -> X
    not(X) >=s 0 -> X <s 0 -> X
    not(X) != 1 -> X == 1 -> X
    not(X) <=u 1 -> X >=u 1 -> X
    not(X) >s 1 -> X <=s -1 -> X

Differential Revision: https://reviews.llvm.org/D114666

Added: 
    

Modified: 
    llvm/lib/Analysis/InstructionSimplify.cpp
    llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index e571c6ba2ff4d..029859f197e01 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2703,9 +2703,17 @@ static Value *simplifyICmpOfBools(CmpInst::Predicate Pred, Value *LHS,
   if (!OpTy->isIntOrIntVectorTy(1))
     return nullptr;
 
-  // A boolean compared to true/false can be simplified in 14 out of the 20
-  // (10 predicates * 2 constants) possible combinations. Cases not handled here
-  // require a 'not' of the LHS, so those must be transformed in InstCombine.
+  // A boolean compared to true/false can be reduced in 14 out of the 20
+  // (10 predicates * 2 constants) possible combinations. The other
+  // 6 cases require a 'not' of the LHS.
+
+  auto ExtractNotLHS = [](Value *V) -> Value * {
+    Value *X;
+    if (match(V, m_Not(m_Value(X))))
+      return X;
+    return nullptr;
+  };
+
   if (match(RHS, m_Zero())) {
     switch (Pred) {
     case CmpInst::ICMP_NE:  // X !=  0 -> X
@@ -2713,6 +2721,13 @@ static Value *simplifyICmpOfBools(CmpInst::Predicate Pred, Value *LHS,
     case CmpInst::ICMP_SLT: // X <s  0 -> X
       return LHS;
 
+    case CmpInst::ICMP_EQ:  // not(X) ==  0 -> X != 0 -> X
+    case CmpInst::ICMP_ULE: // not(X) <=u 0 -> X >u 0 -> X
+    case CmpInst::ICMP_SGE: // not(X) >=s 0 -> X <s 0 -> X
+      if (Value *X = ExtractNotLHS(LHS))
+        return X;
+      break;
+
     case CmpInst::ICMP_ULT: // X <u  0 -> false
     case CmpInst::ICMP_SGT: // X >s  0 -> false
       return getFalse(ITy);
@@ -2730,6 +2745,13 @@ static Value *simplifyICmpOfBools(CmpInst::Predicate Pred, Value *LHS,
     case CmpInst::ICMP_SLE: // X <=s -1 -> X
       return LHS;
 
+    case CmpInst::ICMP_NE:  // not(X) !=  1 -> X ==   1 -> X
+    case CmpInst::ICMP_ULT: // not(X) <=u 1 -> X >=u  1 -> X
+    case CmpInst::ICMP_SGT: // not(X) >s  1 -> X <=s -1 -> X
+      if (Value *X = ExtractNotLHS(LHS))
+        return X;
+      break;
+
     case CmpInst::ICMP_UGT: // X >u   1 -> false
     case CmpInst::ICMP_SLT: // X <s  -1 -> false
       return getFalse(ITy);

diff  --git a/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll b/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll
index b631c6bb5c895..855647dfe1444 100644
--- a/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp-not-bool-constant.ll
@@ -2,7 +2,7 @@
 ; RUN: opt < %s -instsimplify -S | FileCheck %s
 
 ; Test all integer predicates with bool types and true/false constants,
-; with not on LHS (icmp pred (xor X, true), true|false).
+; with not on LHS (icmp pred not(X), true|false).
 ; Use vectors to provide test coverage that is not duplicated in other folds.
 
 define <2 x i1> @eq_t_not(<2 x i1> %a) {
@@ -17,26 +17,58 @@ define <2 x i1> @eq_t_not(<2 x i1> %a) {
 
 define <2 x i1> @eq_f_not(<2 x i1> %a) {
 ; CHECK-LABEL: @eq_f_not(
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i1> [[NOT]], zeroinitializer
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
   %not = xor <2 x i1> %a, <i1 true, i1 true>
   %r = icmp eq <2 x i1> %not, <i1 false, i1 false>
   ret <2 x i1> %r
 }
 
+define <2 x i1> @eq_f_not_swap(<2 x i1> %a) {
+; CHECK-LABEL: @eq_f_not_swap(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> <i1 true, i1 true>, %a
+  %r = icmp eq <2 x i1> %not, <i1 false, i1 false>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @eq_f_not_undef(<2 x i1> %a) {
+; CHECK-LABEL: @eq_f_not_undef(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> %a, <i1 undef, i1 true>
+  %r = icmp eq <2 x i1> %not, <i1 false, i1 false>
+  ret <2 x i1> %r
+}
+
 define <2 x i1> @ne_t_not(<2 x i1> %a) {
 ; CHECK-LABEL: @ne_t_not(
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i1> [[NOT]], <i1 true, i1 true>
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
   %not = xor <2 x i1> %a, <i1 true, i1 true>
   %r = icmp ne <2 x i1> %not, <i1 true, i1 true>
   ret <2 x i1> %r
 }
 
+define <2 x i1> @ne_t_not_swap(<2 x i1> %a) {
+; CHECK-LABEL: @ne_t_not_swap(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> <i1 true, i1 true>, %a
+  %r = icmp ne <2 x i1> %not, <i1 true, i1 true>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @ne_t_not_undef(<2 x i1> %a) {
+; CHECK-LABEL: @ne_t_not_undef(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> %a, <i1 undef, i1 true>
+  %r = icmp ne <2 x i1> %not, <i1 true, i1 true>
+  ret <2 x i1> %r
+}
+
 define <2 x i1> @ne_f_not(<2 x i1> %a) {
 ; CHECK-LABEL: @ne_f_not(
 ; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
@@ -68,15 +100,31 @@ define <2 x i1> @ugt_f_not(<2 x i1> %a) {
 
 define <2 x i1> @ult_t_not(<2 x i1> %a) {
 ; CHECK-LABEL: @ult_t_not(
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i1> [[NOT]], <i1 true, i1 true>
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
   %not = xor <2 x i1> %a, <i1 true, i1 true>
   %r = icmp ult <2 x i1> %not, <i1 true, i1 true>
   ret <2 x i1> %r
 }
 
+define <2 x i1> @ult_t_not_swap(<2 x i1> %a) {
+; CHECK-LABEL: @ult_t_not_swap(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> <i1 true, i1 true>, %a
+  %r = icmp ult <2 x i1> %not, <i1 true, i1 true>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @ult_t_not_undef(<2 x i1> %a) {
+; CHECK-LABEL: @ult_t_not_undef(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> %a, <i1 undef, i1 true>
+  %r = icmp ult <2 x i1> %not, <i1 true, i1 true>
+  ret <2 x i1> %r
+}
+
 define <2 x i1> @ult_f_not(<2 x i1> %a) {
 ; CHECK-LABEL: @ult_f_not(
 ; CHECK-NEXT:    ret <2 x i1> zeroinitializer
@@ -88,15 +136,31 @@ define <2 x i1> @ult_f_not(<2 x i1> %a) {
 
 define <2 x i1> @sgt_t_not(<2 x i1> %a) {
 ; CHECK-LABEL: @sgt_t_not(
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i1> [[NOT]], <i1 true, i1 true>
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
   %not = xor <2 x i1> %a, <i1 true, i1 true>
   %r = icmp sgt <2 x i1> %not, <i1 true, i1 true>
   ret <2 x i1> %r
 }
 
+define <2 x i1> @sgt_t_not_swap(<2 x i1> %a) {
+; CHECK-LABEL: @sgt_t_not_swap(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> <i1 true, i1 true>, %a
+  %r = icmp sgt <2 x i1> %not, <i1 true, i1 true>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @sgt_t_not_undef(<2 x i1> %a) {
+; CHECK-LABEL: @sgt_t_not_undef(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> %a, <i1 undef, i1 true>
+  %r = icmp sgt <2 x i1> %not, <i1 true, i1 true>
+  ret <2 x i1> %r
+}
+
 define <2 x i1> @sgt_f_not(<2 x i1> %a) {
 ; CHECK-LABEL: @sgt_f_not(
 ; CHECK-NEXT:    ret <2 x i1> zeroinitializer
@@ -155,15 +219,31 @@ define <2 x i1> @ule_t_not(<2 x i1> %a) {
 
 define <2 x i1> @ule_f_not(<2 x i1> %a) {
 ; CHECK-LABEL: @ule_f_not(
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[R:%.*]] = icmp ule <2 x i1> [[NOT]], zeroinitializer
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
   %not = xor <2 x i1> %a, <i1 true, i1 true>
   %r = icmp ule <2 x i1> %not, <i1 false, i1 false>
   ret <2 x i1> %r
 }
 
+define <2 x i1> @ule_f_not_swap(<2 x i1> %a) {
+; CHECK-LABEL: @ule_f_not_swap(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> <i1 true, i1 true>, %a
+  %r = icmp ule <2 x i1> %not, <i1 false, i1 false>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @ule_f_not_undef(<2 x i1> %a) {
+; CHECK-LABEL: @ule_f_not_undef(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> %a, <i1 undef, i1 true>
+  %r = icmp ule <2 x i1> %not, <i1 false, i1 false>
+  ret <2 x i1> %r
+}
+
 define <2 x i1> @sge_t_not(<2 x i1> %a) {
 ; CHECK-LABEL: @sge_t_not(
 ; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
@@ -175,15 +255,31 @@ define <2 x i1> @sge_t_not(<2 x i1> %a) {
 
 define <2 x i1> @sge_f_not(<2 x i1> %a) {
 ; CHECK-LABEL: @sge_f_not(
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>
-; CHECK-NEXT:    [[R:%.*]] = icmp sge <2 x i1> [[NOT]], zeroinitializer
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
 ;
   %not = xor <2 x i1> %a, <i1 true, i1 true>
   %r = icmp sge <2 x i1> %not, <i1 false, i1 false>
   ret <2 x i1> %r
 }
 
+define <2 x i1> @sge_f_not_swap(<2 x i1> %a) {
+; CHECK-LABEL: @sge_f_not_swap(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> <i1 true, i1 true>, %a
+  %r = icmp sge <2 x i1> %not, <i1 false, i1 false>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @sge_f_not_undef(<2 x i1> %a) {
+; CHECK-LABEL: @sge_f_not_undef(
+; CHECK-NEXT:    ret <2 x i1> [[A:%.*]]
+;
+  %not = xor <2 x i1> %a, <i1 undef, i1 true>
+  %r = icmp sge <2 x i1> %not, <i1 false, i1 false>
+  ret <2 x i1> %r
+}
+
 define <2 x i1> @sle_t_not(<2 x i1> %a) {
 ; CHECK-LABEL: @sle_t_not(
 ; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[A:%.*]], <i1 true, i1 true>


        


More information about the llvm-commits mailing list