[llvm] goldsteinn/icmp lowbit mask (PR #81562)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 12 17:45:27 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-ir
Author: None (goldsteinn)
<details>
<summary>Changes</summary>
- [InstCombine] Add tests for expanding `foldICmpWithLowBitMaskedVal`; NFC
- [InstCombine] Improve mask detection in `foldICmpWithLowBitMaskedVal`
- [InstCombine] Recognize `(icmp eq/ne (and X, ~Mask), 0)` pattern in `foldICmpWithLowBitMaskedVal`
---
Patch is 47.65 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81562.diff
17 Files Affected:
- (modified) llvm/include/llvm/IR/PatternMatch.h (+25)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+145-15)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-eq-to-icmp-ule.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ne-to-icmp-ugt.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sge-to-icmp-sle.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sgt-to-icmp-sgt.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sle-to-icmp-sle.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-slt-to-icmp-sgt.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll (+1-2)
- (modified) llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll (+1-2)
- (added) llvm/test/Transforms/InstCombine/icmp-and-lowbit-mask.ll (+629)
- (modified) llvm/test/Transforms/InstCombine/lshr-and-negC-icmpeq-zero.ll (+3-6)
- (modified) llvm/test/Transforms/InstCombine/lshr-and-signbit-icmpeq-zero.ll (+3-6)
- (modified) llvm/test/Transforms/InstCombine/shl-and-negC-icmpeq-zero.ll (+3-6)
- (modified) llvm/test/Transforms/InstCombine/shl-and-signbit-icmpeq-zero.ll (+3-6)
``````````diff
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index fed552414298ad..487ae170210de9 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -564,6 +564,19 @@ inline api_pred_ty<is_negated_power2> m_NegatedPower2(const APInt *&V) {
return V;
}
+struct is_negated_power2_or_zero {
+ bool isValue(const APInt &C) { return !C || C.isNegatedPowerOf2(); }
+};
+/// Match a integer or vector negated power-of-2.
+/// For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<is_negated_power2_or_zero> m_NegatedPower2OrZero() {
+ return cst_pred_ty<is_negated_power2_or_zero>();
+}
+inline api_pred_ty<is_negated_power2_or_zero>
+m_NegatedPower2OrZero(const APInt *&V) {
+ return V;
+}
+
struct is_power2_or_zero {
bool isValue(const APInt &C) { return !C || C.isPowerOf2(); }
};
@@ -595,6 +608,18 @@ inline cst_pred_ty<is_lowbit_mask> m_LowBitMask() {
}
inline api_pred_ty<is_lowbit_mask> m_LowBitMask(const APInt *&V) { return V; }
+struct is_lowbit_mask_or_zero {
+ bool isValue(const APInt &C) { return !C || C.isMask(); }
+};
+/// Match an integer or vector with only the low bit(s) set.
+/// For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<is_lowbit_mask_or_zero> m_LowBitMaskOrZero() {
+ return cst_pred_ty<is_lowbit_mask_or_zero>();
+}
+inline api_pred_ty<is_lowbit_mask_or_zero> m_LowBitMaskOrZero(const APInt *&V) {
+ return V;
+}
+
struct icmp_pred_with_threshold {
ICmpInst::Predicate Pred;
const APInt *Thr;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 280c4d77b6dfca..b33004aefb7405 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4068,11 +4068,115 @@ Instruction *InstCombinerImpl::foldSelectICmp(ICmpInst::Predicate Pred,
return nullptr;
}
+// Returns of V is a Mask ((X + 1) & X == 0) or ~Mask (-Pow2OrZero)
+static bool isMaskOrZero(const Value *V, bool Not, const SimplifyQuery &Q,
+ unsigned Depth = 0) {
+ if (Not ? match(V, m_NegatedPower2OrZero()) : match(V, m_LowBitMaskOrZero()))
+ return true;
+ if (V->getType()->getScalarSizeInBits() == 1)
+ return true;
+ if (Depth++ >= MaxAnalysisRecursionDepth)
+ return false;
+ Value *X;
+ if (match(V, m_Not(m_Value(X))))
+ return isMaskOrZero(X, !Not, Q, Depth);
+ const Operator *I = dyn_cast<Operator>(V);
+ if (I == nullptr)
+ return false;
+ switch (I->getOpcode()) {
+ case Instruction::ZExt:
+ // ZExt(Mask) is a Mask.
+ return !Not && isMaskOrZero(I->getOperand(0), Not, Q, Depth);
+ case Instruction::SExt:
+ // SExt(Mask) is a Mask.
+ // SExt(~Mask) is a ~Mask.
+ return isMaskOrZero(I->getOperand(0), Not, Q, Depth);
+ case Instruction::And:
+ case Instruction::Or:
+ // Mask0 | Mask1 is a Mask.
+ // Mask0 & Mask1 is a Mask.
+ // ~Mask0 | ~Mask1 is a ~Mask.
+ // ~Mask0 & ~Mask1 is a ~Mask.
+ return isMaskOrZero(I->getOperand(1), Not, Q, Depth) &&
+ isMaskOrZero(I->getOperand(0), Not, Q, Depth);
+ case Instruction::Xor:
+ // (X ^ (X - 1)) is a Mask
+ return match(V, m_c_Xor(m_Value(X), m_Add(m_Deferred(X), m_AllOnes())));
+ case Instruction::Select:
+ // c ? Mask0 : Mask1 is a Mask.
+ return isMaskOrZero(I->getOperand(1), Not, Q, Depth) &&
+ isMaskOrZero(I->getOperand(2), Not, Q, Depth);
+ case Instruction::Shl:
+ if (Not) {
+ // (-1 >> X) << X is ~Mask
+ if (match(I->getOperand(0),
+ m_Shr(m_AllOnes(), m_Specific(I->getOperand(1)))))
+ return true;
+
+ // (~Mask) << X is a ~Mask.
+ return isMaskOrZero(I->getOperand(0), Not, Q, Depth);
+ }
+ break;
+ case Instruction::LShr:
+ if (!Not) {
+ // (-1 << X) >> X is a Mask
+ if (match(I->getOperand(0),
+ m_Shl(m_AllOnes(), m_Specific(I->getOperand(1)))))
+ return true;
+ // Mask >> X is a Mask.
+ return isMaskOrZero(I->getOperand(0), Not, Q, Depth);
+ }
+ return false;
+ case Instruction::AShr:
+ // Mask s>> X is a Mask.
+ // ~Mask s>> X is a ~Mask.
+ return isMaskOrZero(I->getOperand(0), Not, Q, Depth);
+ case Instruction::Add:
+ // Pow2 - 1 is a Mask.
+ if (!Not && match(I->getOperand(1), m_AllOnes()))
+ return isKnownToBeAPowerOfTwo(I->getOperand(0), Q.DL, /*OrZero*/ true,
+ Depth, Q.AC, Q.CxtI, Q.DT);
+ break;
+ case Instruction::Sub:
+ // -Pow2 is a ~Mask.
+ if (Not && match(I->getOperand(0), m_Zero()))
+ return isKnownToBeAPowerOfTwo(I->getOperand(1), Q.DL, /*OrZero*/ true,
+ Depth, Q.AC, Q.CxtI, Q.DT);
+ break;
+ case Instruction::Invoke:
+ case Instruction::Call: {
+ if (auto *II = dyn_cast<IntrinsicInst>(I)) {
+ switch (II->getIntrinsicID()) {
+ // min/max(Mask0, Mask1) is a Mask.
+ // min/max(~Mask0, ~Mask1) is a ~Mask.
+ case Intrinsic::umax:
+ case Intrinsic::smax:
+ case Intrinsic::umin:
+ case Intrinsic::smin:
+ return isMaskOrZero(II->getArgOperand(1), Not, Q, Depth) &&
+ isMaskOrZero(II->getArgOperand(0), Not, Q, Depth);
+
+ // In the context of masks, bitreverse(Mask) == ~Mask
+ case Intrinsic::bitreverse:
+ return isMaskOrZero(II->getArgOperand(0), !Not, Q, Depth);
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
/// Some comparisons can be simplified.
/// In this case, we are looking for comparisons that look like
/// a check for a lossy truncation.
/// Folds:
/// icmp SrcPred (x & Mask), x to icmp DstPred x, Mask
+/// icmp eq/ne (x & ~Mask), 0 to icmp DstPred x, Mask
/// Where Mask is some pattern that produces all-ones in low bits:
/// (-1 >> y)
/// ((-1 << y) >> y) <- non-canonical, has extra uses
@@ -4081,21 +4185,45 @@ Instruction *InstCombinerImpl::foldSelectICmp(ICmpInst::Predicate Pred,
/// The Mask can be a constant, too.
/// For some predicates, the operands are commutative.
/// For others, x can only be on a specific side.
-static Value *foldICmpWithLowBitMaskedVal(ICmpInst &I,
- InstCombiner::BuilderTy &Builder) {
+static Value *foldICmpWithLowBitMaskedVal(ICmpInst &I, const SimplifyQuery &Q,
+ InstCombiner &IC) {
+
+ Value *X, *M;
+ ICmpInst::Predicate Pred = I.getPredicate();
ICmpInst::Predicate SrcPred;
- Value *X, *M, *Y;
- auto m_VariableMask = m_CombineOr(
- m_CombineOr(m_Not(m_Shl(m_AllOnes(), m_Value())),
- m_Add(m_Shl(m_One(), m_Value()), m_AllOnes())),
- m_CombineOr(m_LShr(m_AllOnes(), m_Value()),
- m_LShr(m_Shl(m_AllOnes(), m_Value(Y)), m_Deferred(Y))));
- auto m_Mask = m_CombineOr(m_VariableMask, m_LowBitMask());
- if (!match(&I, m_c_ICmp(SrcPred,
- m_c_And(m_CombineAnd(m_Mask, m_Value(M)), m_Value(X)),
- m_Deferred(X))))
- return nullptr;
+ bool NeedsNot = false;
+
+ auto CheckMask = [&](Value *V, bool Not) {
+ if (!ICmpInst::isSigned(Pred))
+ return isMaskOrZero(V, Not, Q);
+ return Not ? match(V, m_NegatedPower2OrZero())
+ : match(V, m_LowBitMaskOrZero());
+ };
+
+ auto TryMatch = [&](unsigned OpNo) {
+ SrcPred = Pred;
+ if (match(I.getOperand(OpNo),
+ m_c_And(m_Specific(I.getOperand(1 - OpNo)), m_Value(M)))) {
+ X = I.getOperand(1 - OpNo);
+ if (OpNo)
+ SrcPred = ICmpInst::getSwappedPredicate(Pred);
+ return CheckMask(M, /*Not*/ false);
+ }
+ if (OpNo == 1 && match(I.getOperand(1), m_Zero()) &&
+ ICmpInst::isEquality(Pred) &&
+ match(I.getOperand(0), m_OneUse(m_And(m_Value(X), m_Value(M))))) {
+ NeedsNot = true;
+ if (IC.isFreeToInvert(X, X->hasOneUse()) && CheckMask(X, /*Not*/ true)) {
+ std::swap(X, M);
+ return true;
+ }
+ return IC.isFreeToInvert(M, M->hasOneUse()) && CheckMask(M, /*Not*/ true);
+ }
+ return false;
+ };
+ if (!TryMatch(0) && !TryMatch(1))
+ return nullptr;
ICmpInst::Predicate DstPred;
switch (SrcPred) {
case ICmpInst::Predicate::ICMP_EQ:
@@ -4163,7 +4291,9 @@ static Value *foldICmpWithLowBitMaskedVal(ICmpInst &I,
M = Constant::replaceUndefsWith(VecC, SafeReplacementConstant);
}
- return Builder.CreateICmp(DstPred, X, M);
+ if (NeedsNot)
+ M = IC.Builder.CreateNot(M);
+ return IC.Builder.CreateICmp(DstPred, X, M);
}
/// Some comparisons can be simplified.
@@ -5080,7 +5210,7 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
if (Value *V = foldMultiplicationOverflowCheck(I))
return replaceInstUsesWith(I, V);
- if (Value *V = foldICmpWithLowBitMaskedVal(I, Builder))
+ if (Value *V = foldICmpWithLowBitMaskedVal(I, Q, *this))
return replaceInstUsesWith(I, V);
if (Instruction *R = foldICmpAndXX(I, Q, *this))
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-eq-to-icmp-ule.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-eq-to-icmp-ule.ll
index a957fb2d088ef4..5b7a99d53c308c 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-eq-to-icmp-ule.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-eq-to-icmp-ule.ll
@@ -62,8 +62,7 @@ define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
-; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -4, i8 -1>
-; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT: [[RET:%.*]] = icmp ult <2 x i8> [[X:%.*]], <i8 4, i8 1>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ne-to-icmp-ugt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ne-to-icmp-ugt.ll
index 57361cdf38977c..160d968b9ac4c7 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ne-to-icmp-ugt.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ne-to-icmp-ugt.ll
@@ -62,8 +62,7 @@ define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
-; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -4, i8 -1>
-; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT: [[RET:%.*]] = icmp ugt <2 x i8> [[X:%.*]], <i8 3, i8 0>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sge-to-icmp-sle.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sge-to-icmp-sle.ll
index 0dfc9f51baf9c2..60921042d52435 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sge-to-icmp-sle.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sge-to-icmp-sle.ll
@@ -50,8 +50,7 @@ define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
define <2 x i1> @p2_vec_nonsplat_edgecase(<2 x i8> %x) {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase(
-; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 0>
-; CHECK-NEXT: [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]]
+; CHECK-NEXT: [[RET:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 4, i8 1>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sgt-to-icmp-sgt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sgt-to-icmp-sgt.ll
index e0893ce4cf2ecb..6345e70d7220e2 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sgt-to-icmp-sgt.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sgt-to-icmp-sgt.ll
@@ -63,8 +63,7 @@ define <2 x i1> @p2_vec_nonsplat() {
define <2 x i1> @p2_vec_nonsplat_edgecase() {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase(
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
-; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], <i8 3, i8 0>
-; CHECK-NEXT: [[RET:%.*]] = icmp sgt <2 x i8> [[X]], [[TMP0]]
+; CHECK-NEXT: [[RET:%.*]] = icmp sgt <2 x i8> [[X]], <i8 3, i8 0>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%x = call <2 x i8> @gen2x8()
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sle-to-icmp-sle.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sle-to-icmp-sle.ll
index 81887a39091573..b7aec53fed6760 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sle-to-icmp-sle.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-sle-to-icmp-sle.ll
@@ -63,8 +63,7 @@ define <2 x i1> @p2_vec_nonsplat() {
define <2 x i1> @p2_vec_nonsplat_edgecase() {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase(
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
-; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], <i8 3, i8 0>
-; CHECK-NEXT: [[RET:%.*]] = icmp sle <2 x i8> [[X]], [[TMP0]]
+; CHECK-NEXT: [[RET:%.*]] = icmp slt <2 x i8> [[X]], <i8 4, i8 1>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%x = call <2 x i8> @gen2x8()
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-slt-to-icmp-sgt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-slt-to-icmp-sgt.ll
index 8ce8687f198446..56661d335c4f60 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-slt-to-icmp-sgt.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-slt-to-icmp-sgt.ll
@@ -50,8 +50,7 @@ define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
define <2 x i1> @p2_vec_nonsplat_edgecase(<2 x i8> %x) {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase(
-; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 0>
-; CHECK-NEXT: [[RET:%.*]] = icmp slt <2 x i8> [[TMP0]], [[X]]
+; CHECK-NEXT: [[RET:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 3, i8 0>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll
index ff09e255185b5a..a93e8f779435fc 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll
@@ -62,8 +62,7 @@ define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
-; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -4, i8 -1>
-; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT: [[RET:%.*]] = icmp ult <2 x i8> [[X:%.*]], <i8 4, i8 1>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll
index 4ad04710fd7bb9..73ea4d456d2462 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll
@@ -75,8 +75,7 @@ define <2 x i1> @p2_vec_nonsplat() {
define <2 x i1> @p2_vec_nonsplat_edgecase0() {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
-; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], <i8 -4, i8 -1>
-; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT: [[RET:%.*]] = icmp ugt <2 x i8> [[X]], <i8 3, i8 0>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%x = call <2 x i8> @gen2x8()
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll
index 8e513dcbf4ef3a..53886b5f2dc9c3 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll
@@ -75,8 +75,7 @@ define <2 x i1> @p2_vec_nonsplat() {
define <2 x i1> @p2_vec_nonsplat_edgecase0() {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8()
-; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X]], <i8 -4, i8 -1>
-; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT: [[RET:%.*]] = icmp ult <2 x i8> [[X]], <i8 4, i8 1>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%x = call <2 x i8> @gen2x8()
diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll
index d02ecf6965e878..d66be571008c2f 100644
--- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll
+++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll
@@ -62,8 +62,7 @@ define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) {
; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
-; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -4, i8 -1>
-; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer
+; CHECK-NEXT: [[RET:%.*]] = icmp ugt <2 x i8> [[X:%.*]], <i8 3, i8 0>
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%tmp0 = and <2 x i8> %x, <i8 3, i8 0>
diff --git a/llvm/test/Transforms/InstCombine/icmp-and-lowbit-mask.ll b/llvm/test/Transforms/InstCombine/icmp-and-lowbit-mask.ll
new file mode 100644
index 00000000000000..b06efaac25d169
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-and-lowbit-mask.ll
@@ -0,0 +1,629 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @llvm.assume(i1)
+declare i8 @llvm.ctpop.i8(i8)
+declare i8 @llvm.umin.i8(i8, i8)
+declare i8 @llvm.umax.i8(i8, i8)
+declare i8 @llvm.smin.i8(i8, i8)
+declare i8 @llvm.smax.i8(i8, i8)
+declare i8 @llvm.bitreverse.i8(i8)
+declare void @use.i8(i8)
+declare void @use.i16(i16)
+define i1 @src_is_mask_zext(i16 %x_in, i8 %y) {
+; CHECK-LABEL: @src_is_mask_zext(
+; CHECK-NEXT: [[X:%.*]] = xor i16 [[X_IN:%.*]], 123
+; CHECK-NEXT: [[M_IN:%.*]] = lshr i8 -1, [[Y:%.*]]
+; CHECK-NEXT: [[MASK:%.*]] = zext i8 [[M_IN]] to i16
+; CHECK-NEXT: [[R:%.*]] = icmp ule i16 [[X]], [[MASK]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = xor i16 %x_in, 123
+ %m_in = lshr i8 -1, %y
+ %mask = zext i8 %m_in to i16
+
+ %and = and i16 %x, %mask
+ %r = icmp eq i16 %and, %x
+ ret i1 %r
+}
+
+define i1 @src_is_mask_zext_fail_not_mask(i16 %x_in, i8 %y) {
+; CHECK-LABEL: @src_is_mask_zext_fail_not_mask(
+; CHECK-NEXT: [[X:%.*]] = xor i16 [[X_IN:%.*]], 123
+; CHECK-NEXT: [[M_IN:%.*]] = lshr i8 -2, [[Y:%.*]]
+; CHECK-NEXT: [[MASK:%.*]] = zext i8 [[M_IN]] to i16
+; CHECK-NEXT: [[AND:%.*]] = and i16 [[X]], [[MASK]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[X]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = xor i16 %x_in, 123
+ %m_in = lshr i8 -2, %y
+ %mask = zext i8 %m_in to i16
+
+ %and = and i16 %x, %mask
+ %r = icmp eq i16 %and, %x
+ ret i1 %r
+}
+
+define i1 @src_is_mask_sext(i16 %x_in, i8 %y) {
+; CHECK-LABEL: @src_is_mask_sext(
+; CHECK-NEXT: [[X:%.*]] = xor i16 [[X_IN:%.*]], 123
+; CHECK-NEXT: [[M_IN:%.*]] = lshr i8 31, [[Y:%.*]]
+; CHECK-NEXT: [[MASK:%.*]] = zext nneg i8 [[M_IN]] to...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/81562
More information about the llvm-commits
mailing list