[llvm] [InstCombine] Fold (trunc X to i1) & !iszero(X & Pow2)) -> (X & (1 | Pow2)) == (1 | Pow2) (PR #119196)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 9 02:44:46 PST 2024


https://github.com/andjo403 created https://github.com/llvm/llvm-project/pull/119196

Folds the patterns:
not(trunc X to i1) | iszero(X & Pow2) -> (X & (1 | Pow2)) != (1 | Pow2)
(trunc X to i1) & !iszero(X & Pow2)) -> (X & (1 | Pow2)) == (1 | Pow2)

this is the same pattern that foldAndOrOfICmpsOfAndWithPow2 handles but one `!iszero(X & 1)` have been folded to a `trunc X to i1` or `iszero(X & 1)` folded to `not(trunc X to i1)`
around 100 files updated for the llvm-opt-benchmark with like 6 files with some regressions 
like https://alive2.llvm.org/ce/z/SQLjda and https://alive2.llvm.org/ce/z/_Vu4yB
do not know how to handle the regressions feels like for every fold that I add to handle one regressions i gett new regressions.

proof: https://alive2.llvm.org/ce/z/ofzAyQ

>From f73635a5797297019a8578703abd1196ebc433c8 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 8 Dec 2024 20:12:40 +0100
Subject: [PATCH 1/2] [NFC] Pre-commit test Fold not(trunc X to i1) | iszero(X
 & Pow2) -> (X & (1 | Pow2)) != (1 | Pow2)

---
 .../Transforms/InstCombine/onehot_merge.ll    | 312 ++++++++++++++++++
 1 file changed, 312 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/onehot_merge.ll b/llvm/test/Transforms/InstCombine/onehot_merge.ll
index 2e57597455c2cd..4d2ce57293ba3a 100644
--- a/llvm/test/Transforms/InstCombine/onehot_merge.ll
+++ b/llvm/test/Transforms/InstCombine/onehot_merge.ll
@@ -1143,3 +1143,315 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_not_pwr2_logical(i32 %
   %or = select i1 %t2, i1 true, i1 %t4
   ret i1 %or
 }
+
+define i1 @trunc_or_icmp_consts(i8 %k) {
+; CHECK-LABEL: @trunc_or_icmp_consts(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[AND]], 0
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %and = and i8 %k, 8
+  %icmp = icmp eq i8 %and, 0
+  %ret = or i1 %not, %icmp
+  ret i1 %ret
+}
+
+define i1 @icmp_or_trunc_consts(i8 %k) {
+; CHECK-LABEL: @icmp_or_trunc_consts(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[AND]], 0
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[OR]]
+;
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %and = and i8 %k, 8
+  %icmp = icmp eq i8 %and, 0
+  %ret = or i1 %icmp, %not
+  ret i1 %ret
+}
+
+define i1 @trunc_or_icmp(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_or_icmp(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp eq i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %ret = or i1 %icmp, %not
+  ret i1 %ret
+}
+
+define i1 @trunc_logical_or_icmp(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_logical_or_icmp(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp eq i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %ret = select i1 %icmp, i1 true, i1 %not
+  ret i1 %ret
+}
+
+define i1 @icmp_logical_or_trunc(i8 %k, i8 %c1) {
+; CHECK-LABEL: @icmp_logical_or_trunc(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[NOT]], i1 true, i1 [[ICMP]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp eq i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %ret = select i1 %not, i1 true, i1 %icmp
+  ret i1 %ret
+}
+
+define <2 x i1> @trunc_or_icmp_vec(<2 x i8> %k, <2 x i8> %c1) {
+; CHECK-LABEL: @trunc_or_icmp_vec(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw <2 x i8> splat (i8 1), [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and <2 x i8> [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq <2 x i8> [[T1]], zeroinitializer
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i8> [[K]] to <2 x i1>
+; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[TRUNC]], splat (i1 true)
+; CHECK-NEXT:    [[RET:%.*]] = or <2 x i1> [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %t = shl <2 x i8> <i8 1, i8 1>, %c1
+  %t1 = and <2 x i8> %t, %k
+  %icmp = icmp eq <2 x i8> %t1, zeroinitializer
+  %trunc = trunc <2 x i8> %k to <2 x i1>
+  %not = xor <2 x i1> %trunc, <i1 true, i1 true>
+  %ret = or <2 x i1> %icmp, %not
+  ret <2 x i1> %ret
+}
+
+define i1 @neg_trunc_or_icmp_not_pow2(i8 %k, i8 %c1) {
+; CHECK-LABEL: @neg_trunc_or_icmp_not_pow2(
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[C1:%.*]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t1 = and i8 %c1, %k
+  %icmp = icmp eq i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %ret = or i1 %icmp, %not
+  ret i1 %ret
+}
+
+define i1 @neg_trunc_or_icmp_not_trunc(i8 %k, i8 %c1) {
+; CHECK-LABEL: @neg_trunc_or_icmp_not_trunc(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp eq i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %ret = or i1 %icmp, %trunc
+  ret i1 %ret
+}
+
+define i1 @neg_trunc_or_icmp_ne(i8 %k, i8 %c1) {
+; CHECK-LABEL: @neg_trunc_or_icmp_ne(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp ne i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %ret = or i1 %icmp, %not
+  ret i1 %ret
+}
+
+define i1 @trunc_and_icmp_consts(i8 %k) {
+; CHECK-LABEL: @trunc_and_icmp_consts(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[AND]], 0
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %trunc = trunc i8 %k to i1
+  %and = and i8 %k, 8
+  %icmp = icmp ne i8 %and, 0
+  %ret = and i1 %trunc, %icmp
+  ret i1 %ret
+}
+
+define i1 @icmp_and_trunc_consts(i8 %k) {
+; CHECK-LABEL: @icmp_and_trunc_consts(
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[AND]], 0
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %trunc = trunc i8 %k to i1
+  %and = and i8 %k, 8
+  %icmp = icmp ne i8 %and, 0
+  %ret = and i1 %icmp, %trunc
+  ret i1 %ret
+}
+
+define i1 @trunc_and_icmp(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_and_icmp(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp ne i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %ret = and i1 %icmp, %trunc
+  ret i1 %ret
+}
+
+define i1 @trunc_logical_and_icmp(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_logical_and_icmp(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp ne i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %ret = select i1 %icmp, i1 %trunc, i1 false
+  ret i1 %ret
+}
+
+define i1 @icmp_logical_and_trunc(i8 %k, i8 %c1) {
+; CHECK-LABEL: @icmp_logical_and_trunc(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = select i1 [[TRUNC]], i1 [[ICMP]], i1 false
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp ne i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %ret = select i1 %trunc, i1 %icmp, i1 false
+  ret i1 %ret
+}
+
+define <2 x i1> @trunc_and_icmp_vec(<2 x i8> %k, <2 x i8> %c1) {
+; CHECK-LABEL: @trunc_and_icmp_vec(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw <2 x i8> splat (i8 1), [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and <2 x i8> [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne <2 x i8> [[T1]], zeroinitializer
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i8> [[K]] to <2 x i1>
+; CHECK-NEXT:    [[RET:%.*]] = and <2 x i1> [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret <2 x i1> [[RET]]
+;
+  %t = shl <2 x i8> <i8 1, i8 1>, %c1
+  %t1 = and <2 x i8> %t, %k
+  %icmp = icmp ne <2 x i8> %t1, zeroinitializer
+  %trunc = trunc <2 x i8> %k to <2 x i1>
+  %ret = and <2 x i1> %icmp, %trunc
+  ret <2 x i1> %ret
+}
+
+define i1 @trunc_and_icmp_not_pow2(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_and_icmp_not_pow2(
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[C1:%.*]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t1 = and i8 %c1, %k
+  %icmp = icmp ne i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %ret = and i1 %icmp, %trunc
+  ret i1 %ret
+}
+
+define i1 @trunc_and_icmp_not_trunc(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_and_icmp_not_trunc(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp ne i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %not = xor i1 %trunc, true
+  %ret = and i1 %icmp, %not
+  ret i1 %ret
+}
+
+define i1 @trunc_and_icmp_eq(i8 %k, i8 %c1) {
+; CHECK-LABEL: @trunc_and_icmp_eq(
+; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
+; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
+; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
+; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
+; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %t = shl i8 1, %c1
+  %t1 = and i8 %t, %k
+  %icmp = icmp eq i8 %t1, 0
+  %trunc = trunc i8 %k to i1
+  %ret = and i1 %icmp, %trunc
+  ret i1 %ret
+}

>From b0c724b9b2ad47f91eed125ed81c1ff6563b1c1a Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 8 Dec 2024 20:19:17 +0100
Subject: [PATCH 2/2] [InstCombine] Fold not(trunc X to i1) | iszero(X & Pow2)
 -> (X & (1 | Pow2)) != (1 | Pow2)

also folds (trunc X to i1) & !iszero(X & Pow2)) -> (X & (1 | Pow2)) == (1 | Pow2)
---
 .../InstCombine/InstCombineAndOrXor.cpp       | 38 ++++++++
 .../Transforms/InstCombine/onehot_merge.ll    | 88 +++++++------------
 2 files changed, 72 insertions(+), 54 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index b4033fc2a418a1..da58bedbce8b34 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -805,6 +805,40 @@ Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS,
   return nullptr;
 }
 
+// Fold not(trunc X to i1) | iszero(X & Pow2)
+//  -> (X & (1 | Pow2)) != (1 | Pow2)
+// Fold (trunc X to i1) & !iszero(X & Pow2))
+//  -> (X & (1 | Pow2)) == (1 | Pow2)
+static Value *foldTruncAndOrICmpOfAndWithPow2(InstCombiner::BuilderTy &Builder,
+                                              Value *LHS, Value *RHS,
+                                              bool IsAnd, bool IsLogical,
+                                              const SimplifyQuery &Q) {
+  CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
+
+  if (isa<ICmpInst>(LHS))
+    std::swap(LHS, RHS);
+
+  Value *X, *Pow2;
+
+  if ((IsAnd ? match(LHS, m_Trunc(m_Value(X)))
+             : match(LHS, m_Not(m_Trunc(m_Value(X))))) &&
+      match(RHS, m_SpecificICmp(Pred, m_c_And(m_Specific(X), m_Value(Pow2)),
+                                m_ZeroInt())) &&
+      isKnownToBeAPowerOfTwo(Pow2, Q.DL, /*OrZero=*/false, /*Depth=*/0, Q.AC,
+                             Q.CxtI, Q.DT)) {
+    // If this is a logical and/or, then we must prevent propagation of a
+    // poison value from the RHS by inserting freeze.
+    if (IsLogical)
+      Pow2 = Builder.CreateFreeze(Pow2);
+    Value *Mask = Builder.CreateOr(ConstantInt::get(Pow2->getType(), 1), Pow2);
+    Value *Masked = Builder.CreateAnd(X, Mask);
+    auto NewPred = IsAnd ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
+    return Builder.CreateICmp(NewPred, Masked, Mask);
+  }
+
+  return nullptr;
+}
+
 /// General pattern:
 ///   X & Y
 ///
@@ -3541,6 +3575,10 @@ Value *InstCombinerImpl::foldBooleanAndOr(Value *LHS, Value *RHS,
 
   if (Value *Res = foldEqOfParts(LHS, RHS, IsAnd))
     return Res;
+  const SimplifyQuery Q = SQ.getWithInstruction(&I);
+  if (Value *Res = foldTruncAndOrICmpOfAndWithPow2(Builder, LHS, RHS, IsAnd,
+                                                   IsLogical, Q))
+    return Res;
 
   return nullptr;
 }
diff --git a/llvm/test/Transforms/InstCombine/onehot_merge.ll b/llvm/test/Transforms/InstCombine/onehot_merge.ll
index 4d2ce57293ba3a..e4586a231535a3 100644
--- a/llvm/test/Transforms/InstCombine/onehot_merge.ll
+++ b/llvm/test/Transforms/InstCombine/onehot_merge.ll
@@ -1146,11 +1146,8 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_not_pwr2_logical(i32 %
 
 define i1 @trunc_or_icmp_consts(i8 %k) {
 ; CHECK-LABEL: @trunc_or_icmp_consts(
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[AND]], 0
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[K:%.*]], 9
+; CHECK-NEXT:    [[OR:%.*]] = icmp ne i8 [[TMP1]], 9
 ; CHECK-NEXT:    ret i1 [[OR]]
 ;
   %trunc = trunc i8 %k to i1
@@ -1163,11 +1160,8 @@ define i1 @trunc_or_icmp_consts(i8 %k) {
 
 define i1 @icmp_or_trunc_consts(i8 %k) {
 ; CHECK-LABEL: @icmp_or_trunc_consts(
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[AND]], 0
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[K:%.*]], 9
+; CHECK-NEXT:    [[OR:%.*]] = icmp ne i8 [[TMP1]], 9
 ; CHECK-NEXT:    ret i1 [[OR]]
 ;
   %trunc = trunc i8 %k to i1
@@ -1181,11 +1175,9 @@ define i1 @icmp_or_trunc_consts(i8 %k) {
 define i1 @trunc_or_icmp(i8 %k, i8 %c1) {
 ; CHECK-LABEL: @trunc_or_icmp(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
-; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[T]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[K:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %t = shl i8 1, %c1
@@ -1200,11 +1192,9 @@ define i1 @trunc_or_icmp(i8 %k, i8 %c1) {
 define i1 @trunc_logical_or_icmp(i8 %k, i8 %c1) {
 ; CHECK-LABEL: @trunc_logical_or_icmp(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
-; CHECK-NEXT:    [[RET:%.*]] = or i1 [[ICMP]], [[NOT]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[T]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[K:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %t = shl i8 1, %c1
@@ -1219,11 +1209,10 @@ define i1 @trunc_logical_or_icmp(i8 %k, i8 %c1) {
 define i1 @icmp_logical_or_trunc(i8 %k, i8 %c1) {
 ; CHECK-LABEL: @icmp_logical_or_trunc(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq i8 [[T1]], 0
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
-; CHECK-NEXT:    [[NOT:%.*]] = xor i1 [[TRUNC]], true
-; CHECK-NEXT:    [[RET:%.*]] = select i1 [[NOT]], i1 true, i1 [[ICMP]]
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i8 [[T]]
+; CHECK-NEXT:    [[TMP2:%.*]] = or i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP3:%.*]] = and i8 [[K:%.*]], [[TMP2]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne i8 [[TMP3]], [[TMP2]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %t = shl i8 1, %c1
@@ -1238,11 +1227,9 @@ define i1 @icmp_logical_or_trunc(i8 %k, i8 %c1) {
 define <2 x i1> @trunc_or_icmp_vec(<2 x i8> %k, <2 x i8> %c1) {
 ; CHECK-LABEL: @trunc_or_icmp_vec(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw <2 x i8> splat (i8 1), [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and <2 x i8> [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp eq <2 x i8> [[T1]], zeroinitializer
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i8> [[K]] to <2 x i1>
-; CHECK-NEXT:    [[NOT:%.*]] = xor <2 x i1> [[TRUNC]], splat (i1 true)
-; CHECK-NEXT:    [[RET:%.*]] = or <2 x i1> [[ICMP]], [[NOT]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or <2 x i8> [[T]], splat (i8 1)
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i8> [[K:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ne <2 x i8> [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    ret <2 x i1> [[RET]]
 ;
   %t = shl <2 x i8> <i8 1, i8 1>, %c1
@@ -1309,10 +1296,8 @@ define i1 @neg_trunc_or_icmp_ne(i8 %k, i8 %c1) {
 
 define i1 @trunc_and_icmp_consts(i8 %k) {
 ; CHECK-LABEL: @trunc_and_icmp_consts(
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[AND]], 0
-; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[K:%.*]], 9
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP1]], 9
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %trunc = trunc i8 %k to i1
@@ -1324,10 +1309,8 @@ define i1 @trunc_and_icmp_consts(i8 %k) {
 
 define i1 @icmp_and_trunc_consts(i8 %k) {
 ; CHECK-LABEL: @icmp_and_trunc_consts(
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K:%.*]] to i1
-; CHECK-NEXT:    [[AND:%.*]] = and i8 [[K]], 8
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[AND]], 0
-; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[K:%.*]], 9
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP1]], 9
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %trunc = trunc i8 %k to i1
@@ -1340,10 +1323,9 @@ define i1 @icmp_and_trunc_consts(i8 %k) {
 define i1 @trunc_and_icmp(i8 %k, i8 %c1) {
 ; CHECK-LABEL: @trunc_and_icmp(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
-; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[T]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[K:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %t = shl i8 1, %c1
@@ -1357,10 +1339,9 @@ define i1 @trunc_and_icmp(i8 %k, i8 %c1) {
 define i1 @trunc_logical_and_icmp(i8 %k, i8 %c1) {
 ; CHECK-LABEL: @trunc_logical_and_icmp(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
-; CHECK-NEXT:    [[RET:%.*]] = and i1 [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[T]], 1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[K:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %t = shl i8 1, %c1
@@ -1374,10 +1355,10 @@ define i1 @trunc_logical_and_icmp(i8 %k, i8 %c1) {
 define i1 @icmp_logical_and_trunc(i8 %k, i8 %c1) {
 ; CHECK-LABEL: @icmp_logical_and_trunc(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw i8 1, [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and i8 [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne i8 [[T1]], 0
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i8 [[K]] to i1
-; CHECK-NEXT:    [[RET:%.*]] = select i1 [[TRUNC]], i1 [[ICMP]], i1 false
+; CHECK-NEXT:    [[TMP1:%.*]] = freeze i8 [[T]]
+; CHECK-NEXT:    [[TMP2:%.*]] = or i8 [[TMP1]], 1
+; CHECK-NEXT:    [[TMP3:%.*]] = and i8 [[K:%.*]], [[TMP2]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP3]], [[TMP2]]
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %t = shl i8 1, %c1
@@ -1391,10 +1372,9 @@ define i1 @icmp_logical_and_trunc(i8 %k, i8 %c1) {
 define <2 x i1> @trunc_and_icmp_vec(<2 x i8> %k, <2 x i8> %c1) {
 ; CHECK-LABEL: @trunc_and_icmp_vec(
 ; CHECK-NEXT:    [[T:%.*]] = shl nuw <2 x i8> splat (i8 1), [[C1:%.*]]
-; CHECK-NEXT:    [[T1:%.*]] = and <2 x i8> [[T]], [[K:%.*]]
-; CHECK-NEXT:    [[ICMP:%.*]] = icmp ne <2 x i8> [[T1]], zeroinitializer
-; CHECK-NEXT:    [[TRUNC:%.*]] = trunc <2 x i8> [[K]] to <2 x i1>
-; CHECK-NEXT:    [[RET:%.*]] = and <2 x i1> [[ICMP]], [[TRUNC]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or <2 x i8> [[T]], splat (i8 1)
+; CHECK-NEXT:    [[TMP2:%.*]] = and <2 x i8> [[K:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq <2 x i8> [[TMP2]], [[TMP1]]
 ; CHECK-NEXT:    ret <2 x i1> [[RET]]
 ;
   %t = shl <2 x i8> <i8 1, i8 1>, %c1



More information about the llvm-commits mailing list