[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
Sat Dec 14 02:04:11 PST 2024
https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/119196
>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/4] [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/4] [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
>From 266fac9af5e6c1a1f861f09200e3054295b7c970 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 14 Dec 2024 11:01:33 +0100
Subject: [PATCH 3/4] [NFC] Add test for redundant freeze
---
.../Transforms/InstCombine/onehot_merge.ll | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/onehot_merge.ll b/llvm/test/Transforms/InstCombine/onehot_merge.ll
index e4586a231535a3..85c0424a1e482f 100644
--- a/llvm/test/Transforms/InstCombine/onehot_merge.ll
+++ b/llvm/test/Transforms/InstCombine/onehot_merge.ll
@@ -1369,6 +1369,27 @@ define i1 @icmp_logical_and_trunc(i8 %k, i8 %c1) {
ret i1 %ret
}
+define i1 @trunc_logical_and_icmp_and_icmps(i8 %x, i8 %y, i8 %c1) {
+; CHECK-LABEL: @trunc_logical_and_icmp_and_icmps(
+; CHECK-NEXT: [[Z_SHIFT:%.*]] = shl nuw i8 1, [[Z:%.*]]
+; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[Y:%.*]], 42
+; CHECK-NEXT: [[TMP4:%.*]] = freeze i8 [[Z_SHIFT]]
+; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[TMP4]], 1
+; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[TMP3]], i1 [[C1]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+ %t = shl i8 1, %c1
+ %t1 = and i8 %x, %t
+ %trunc = trunc i8 %x to i1
+ %icmp1 = icmp eq i8 %y, 42
+ %and1 = select i1 %trunc, i1 %icmp1, i1 false
+ %icmp2 = icmp ne i8 %t1, 0
+ %and2 = and i1 %icmp2, %and1
+ ret i1 %and2
+}
+
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:%.*]]
>From b781ca8457b03b59c72e86d7eff87c5efe65df72 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 14 Dec 2024 11:03:55 +0100
Subject: [PATCH 4/4] [InstCombine] remove redundant freeze in
foldTruncAndOrICmpOfAndWithPow2
---
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 7 +++++--
llvm/test/Transforms/InstCombine/onehot_merge.ll | 3 +--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index da58bedbce8b34..3688f6a31ceea4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -815,8 +815,11 @@ static Value *foldTruncAndOrICmpOfAndWithPow2(InstCombiner::BuilderTy &Builder,
const SimplifyQuery &Q) {
CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
- if (isa<ICmpInst>(LHS))
+ bool Swapped = false;
+ if (isa<ICmpInst>(LHS)) {
std::swap(LHS, RHS);
+ Swapped = true;
+ }
Value *X, *Pow2;
@@ -828,7 +831,7 @@ static Value *foldTruncAndOrICmpOfAndWithPow2(InstCombiner::BuilderTy &Builder,
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)
+ if (!Swapped && IsLogical)
Pow2 = Builder.CreateFreeze(Pow2);
Value *Mask = Builder.CreateOr(ConstantInt::get(Pow2->getType(), 1), Pow2);
Value *Masked = Builder.CreateAnd(X, Mask);
diff --git a/llvm/test/Transforms/InstCombine/onehot_merge.ll b/llvm/test/Transforms/InstCombine/onehot_merge.ll
index 85c0424a1e482f..be8aa21867ddd8 100644
--- a/llvm/test/Transforms/InstCombine/onehot_merge.ll
+++ b/llvm/test/Transforms/InstCombine/onehot_merge.ll
@@ -1373,8 +1373,7 @@ define i1 @trunc_logical_and_icmp_and_icmps(i8 %x, i8 %y, i8 %c1) {
; CHECK-LABEL: @trunc_logical_and_icmp_and_icmps(
; CHECK-NEXT: [[Z_SHIFT:%.*]] = shl nuw i8 1, [[Z:%.*]]
; CHECK-NEXT: [[C1:%.*]] = icmp eq i8 [[Y:%.*]], 42
-; CHECK-NEXT: [[TMP4:%.*]] = freeze i8 [[Z_SHIFT]]
-; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[TMP4]], 1
+; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[Z_SHIFT]], 1
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
; CHECK-NEXT: [[AND2:%.*]] = select i1 [[TMP3]], i1 [[C1]], i1 false
More information about the llvm-commits
mailing list