[llvm] f9e2fb9 - [InstCombine] combine intersection for inequality icmps

Yingchi Long via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 9 20:51:00 PST 2023


Author: Yingchi Long
Date: 2023-02-10T12:50:39+08:00
New Revision: f9e2fb9d8e59e5a6428727d984c95753d57c3bb8

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

LOG: [InstCombine] combine intersection for inequality icmps

```
define i1 @src(i32 %A) {
  %mask1 = and i32 %A, 15 ; 0x0f
  %tst1 = icmp eq i32 %mask1, 3 ; 0x03
  %mask2 = and i32 %A, 255 ; 0xff
  %tst2 = icmp eq i32 %mask2, 243; 0xf3
  %res = or i1 %tst1, %tst2
  ret i1 %res
}
```

->

```
define i1 @tgt(i32 %A) {
  %1 = and i32 %A, 15
  %res = icmp eq i32 %1, 3
  ret i1 %res
}
```

Proof: https://alive2.llvm.org/ce/z/4AyvcE

Assume that `(B & D) & (C ^ E) == 0`, and `(B & D) == D || (B & D) == B`,
transforms:

```
(icmp ne (A & B), C) & (icmp ne (A & D), E)
-> (icmp ne (A & (B&D)), (C&E))
```

Fixes: https://github.com/llvm/llvm-project/issues/59680

Reviewed By: spatel, bcl5980

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/icmp-logical.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 5b168e4ed0f0..e389f3d6bd09 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -625,7 +625,8 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
       return RHS;
   }
 
-  if (Mask & BMask_Mixed) {
+  if (Mask & (BMask_Mixed | BMask_NotMixed)) {
+    // Mixed:
     // (icmp eq (A & B), C) & (icmp eq (A & D), E)
     // We already know that B & C == C && D & E == E.
     // If we can prove that (B & D) & (C ^ E) == 0, that is, the bits of
@@ -636,24 +637,50 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
     // We can't simply use C and E because we might actually handle
     //   (icmp ne (A & B), B) & (icmp eq (A & D), D)
     // with B and D, having a single bit set.
+
+    // NotMixed:
+    // (icmp ne (A & B), C) & (icmp ne (A & D), E)
+    // -> (icmp ne (A & (B & D)), (C & E))
+    // Check the intersection (B & D) for inequality.
+    // Assume that (B & D) == B || (B & D) == D, i.e B/D is a subset of D/B
+    // and (B & D) & (C ^ E) == 0, bits of C and E, which are shared by both the
+    // B and the D, don't contradict.
+    // Note that we can assume (~B & C) == 0 && (~D & E) == 0, previous
+    // operation should delete these icmps if it hadn't been met.
+
     const APInt *OldConstC, *OldConstE;
     if (!match(C, m_APInt(OldConstC)) || !match(E, m_APInt(OldConstE)))
       return nullptr;
 
-    const APInt ConstC = PredL != NewCC ? *ConstB ^ *OldConstC : *OldConstC;
-    const APInt ConstE = PredR != NewCC ? *ConstD ^ *OldConstE : *OldConstE;
+    auto FoldBMixed = [&](ICmpInst::Predicate CC, bool IsNot) -> Value * {
+      CC = IsNot ? CmpInst::getInversePredicate(CC) : CC;
+      const APInt ConstC = PredL != CC ? *ConstB ^ *OldConstC : *OldConstC;
+      const APInt ConstE = PredR != CC ? *ConstD ^ *OldConstE : *OldConstE;
 
-    // If there is a conflict, we should actually return a false for the
-    // whole construct.
-    if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue())
-      return ConstantInt::get(LHS->getType(), !IsAnd);
+      if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue())
+        return IsNot ? nullptr : ConstantInt::get(LHS->getType(), !IsAnd);
 
-    Value *NewOr1 = Builder.CreateOr(B, D);
-    Value *NewAnd = Builder.CreateAnd(A, NewOr1);
-    Constant *NewOr2 = ConstantInt::get(A->getType(), ConstC | ConstE);
-    return Builder.CreateICmp(NewCC, NewAnd, NewOr2);
-  }
+      if (IsNot && !ConstB->isSubsetOf(*ConstD) && !ConstD->isSubsetOf(*ConstB))
+        return nullptr;
 
+      APInt BD, CE;
+      if (IsNot) {
+        BD = *ConstB & *ConstD;
+        CE = ConstC & ConstE;
+      } else {
+        BD = *ConstB | *ConstD;
+        CE = ConstC | ConstE;
+      }
+      Value *NewAnd = Builder.CreateAnd(A, BD);
+      Value *CEVal = ConstantInt::get(A->getType(), CE);
+      return Builder.CreateICmp(CC, CEVal, NewAnd);
+    };
+
+    if (Mask & BMask_Mixed)
+      return FoldBMixed(NewCC, false);
+    if (Mask & BMask_NotMixed) // can be else also
+      return FoldBMixed(NewCC, true);
+  }
   return nullptr;
 }
 

diff  --git a/llvm/test/Transforms/InstCombine/icmp-logical.ll b/llvm/test/Transforms/InstCombine/icmp-logical.ll
index 705399e3c31b..62342fae5058 100644
--- a/llvm/test/Transforms/InstCombine/icmp-logical.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-logical.ll
@@ -1747,11 +1747,8 @@ define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b_logical(
 
 define i1 @masked_icmps_bmask_notmixed_or(i32 %A) {
 ; CHECK-LABEL: @masked_icmps_bmask_notmixed_or(
-; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 15
-; CHECK-NEXT:    [[TST1:%.*]] = icmp eq i32 [[MASK1]], 3
-; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A]], 255
-; CHECK-NEXT:    [[TST2:%.*]] = icmp eq i32 [[MASK2]], 243
-; CHECK-NEXT:    [[RES:%.*]] = or i1 [[TST1]], [[TST2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT:    [[RES:%.*]] = icmp eq i32 [[TMP1]], 3
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
   %mask1 = and i32 %A, 15 ; 0x0f
@@ -1764,10 +1761,8 @@ define i1 @masked_icmps_bmask_notmixed_or(i32 %A) {
 
 define <2 x i1> @masked_icmps_bmask_notmixed_or_vec(<2 x i8> %A) {
 ; CHECK-LABEL: @masked_icmps_bmask_notmixed_or_vec(
-; CHECK-NEXT:    [[MASK1:%.*]] = and <2 x i8> [[A:%.*]], <i8 15, i8 15>
-; CHECK-NEXT:    [[TST1:%.*]] = icmp eq <2 x i8> [[MASK1]], <i8 3, i8 3>
-; CHECK-NEXT:    [[TST2:%.*]] = icmp eq <2 x i8> [[A]], <i8 -13, i8 -13>
-; CHECK-NEXT:    [[RES:%.*]] = or <2 x i1> [[TST1]], [[TST2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[A:%.*]], <i8 15, i8 15>
+; CHECK-NEXT:    [[RES:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 3, i8 3>
 ; CHECK-NEXT:    ret <2 x i1> [[RES]]
 ;
   %mask1 = and <2 x i8> %A, <i8 15, i8 15> ; 0x0f
@@ -1829,11 +1824,8 @@ define i1 @masked_icmps_bmask_notmixed_or_contradict_notoptimized(i32 %A) {
 
 define i1 @masked_icmps_bmask_notmixed_and(i32 %A) {
 ; CHECK-LABEL: @masked_icmps_bmask_notmixed_and(
-; CHECK-NEXT:    [[MASK1:%.*]] = and i32 [[A:%.*]], 15
-; CHECK-NEXT:    [[TST1:%.*]] = icmp ne i32 [[MASK1]], 3
-; CHECK-NEXT:    [[MASK2:%.*]] = and i32 [[A]], 255
-; CHECK-NEXT:    [[TST2:%.*]] = icmp ne i32 [[MASK2]], 243
-; CHECK-NEXT:    [[RES:%.*]] = and i1 [[TST1]], [[TST2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[A:%.*]], 15
+; CHECK-NEXT:    [[RES:%.*]] = icmp ne i32 [[TMP1]], 3
 ; CHECK-NEXT:    ret i1 [[RES]]
 ;
   %mask1 = and i32 %A, 15 ; 0x0f


        


More information about the llvm-commits mailing list