[llvm] [InstCombine] Strip off sign bit preserving or flipping operations (PR #141974)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Fri May 30 01:08:53 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/141974
>From 203ca20171c66c2cbc20ffb102dcf047b90fda54 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 30 May 2025 00:21:59 +0800
Subject: [PATCH 1/2] [InstCombine] Strip off sign bit preserving or flipping
operations
---
.../InstCombine/InstCombineCompares.cpp | 97 ++++++++++++-------
.../InstCombine/InstCombineInternal.h | 6 ++
2 files changed, 67 insertions(+), 36 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index bdc7a49700cfc..c585b095b1ede 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -72,32 +72,6 @@ static bool hasBranchUse(ICmpInst &I) {
return false;
}
-/// Returns true if the exploded icmp can be expressed as a signed comparison
-/// to zero and updates the predicate accordingly.
-/// The signedness of the comparison is preserved.
-/// TODO: Refactor with decomposeBitTestICmp()?
-static bool isSignTest(ICmpInst::Predicate &Pred, const APInt &C) {
- if (!ICmpInst::isSigned(Pred))
- return false;
-
- if (C.isZero())
- return ICmpInst::isRelational(Pred);
-
- if (C.isOne()) {
- if (Pred == ICmpInst::ICMP_SLT) {
- Pred = ICmpInst::ICMP_SLE;
- return true;
- }
- } else if (C.isAllOnes()) {
- if (Pred == ICmpInst::ICMP_SGT) {
- Pred = ICmpInst::ICMP_SGE;
- return true;
- }
- }
-
- return false;
-}
-
/// This is called when we see this pattern:
/// cmp pred (load (gep GV, ...)), cmpcst
/// where GV is a global variable with a constant initializer. Try to simplify
@@ -2188,16 +2162,6 @@ Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp,
if (!match(Mul->getOperand(1), m_APInt(MulC)))
return nullptr;
- // If this is a test of the sign bit and the multiply is sign-preserving with
- // a constant operand, use the multiply LHS operand instead:
- // (X * +MulC) < 0 --> X < 0
- // (X * -MulC) < 0 --> X > 0
- if (isSignTest(Pred, C) && Mul->hasNoSignedWrap()) {
- if (MulC->isNegative())
- Pred = ICmpInst::getSwappedPredicate(Pred);
- return new ICmpInst(Pred, X, ConstantInt::getNullValue(MulTy));
- }
-
if (MulC->isZero())
return nullptr;
@@ -3545,12 +3509,73 @@ Instruction *InstCombinerImpl::foldICmpBitCast(ICmpInst &Cmp) {
return nullptr;
}
+std::pair<Value *, bool>
+InstCombinerImpl::stripSignBitPreservingOrFlippingOperations(Value *X,
+ unsigned Depth) {
+ if (!X->hasOneUse() || Depth++ >= MaxAnalysisRecursionDepth)
+ return {X, false};
+
+ auto FlipSign = [](std::pair<Value *, bool> P, bool Flip) {
+ return std::make_pair(P.first, P.second ^ Flip);
+ };
+
+ Value *V;
+ const APInt *C;
+ if (match(X, m_NSWTrunc(m_Value(V))) &&
+ shouldChangeType(X->getType(), V->getType()))
+ return stripSignBitPreservingOrFlippingOperations(V, Depth);
+
+ if (match(X, m_SExt(m_Value(V))) &&
+ shouldChangeType(X->getType(), V->getType()))
+ return stripSignBitPreservingOrFlippingOperations(V, Depth);
+
+ if (match(X, m_Xor(m_Value(V), m_APInt(C))))
+ return FlipSign(stripSignBitPreservingOrFlippingOperations(V, Depth),
+ C->isNegative());
+
+ if (match(X, m_AShr(m_Value(V), m_Value())))
+ return stripSignBitPreservingOrFlippingOperations(V, Depth);
+
+ if (match(X, m_NSWSub(m_Zero(), m_Value(V))))
+ return FlipSign(stripSignBitPreservingOrFlippingOperations(V, Depth),
+ /*Flip=*/true);
+
+ if (match(X, m_NSWShl(m_Value(V), m_Value())))
+ return stripSignBitPreservingOrFlippingOperations(V, Depth);
+
+ if (match(X, m_NSWMul(m_Value(V), m_APInt(C))) && !C->isZero())
+ return FlipSign(stripSignBitPreservingOrFlippingOperations(V, Depth),
+ C->isNegative());
+
+ if (match(X, m_SMax(m_Value(V), m_Negative())))
+ return stripSignBitPreservingOrFlippingOperations(V, Depth);
+
+ if (match(X, m_SMin(m_Value(V), m_StrictlyPositive())))
+ return stripSignBitPreservingOrFlippingOperations(V, Depth);
+
+ return {X, false};
+}
+
/// Try to fold integer comparisons with a constant operand: icmp Pred X, C
/// where X is some kind of instruction.
Instruction *InstCombinerImpl::foldICmpInstWithConstant(ICmpInst &Cmp) {
const APInt *C;
if (match(Cmp.getOperand(1), m_APInt(C))) {
+ bool TrueIfSigned = false;
+ // Strip off sign bit preserving/flipping operations.
+ if (isSignBitCheck(Cmp.getPredicate(), *C, TrueIfSigned)) {
+ auto [X, FlipSign] = stripSignBitPreservingOrFlippingOperations(
+ Cmp.getOperand(0), /*Depth=*/0);
+ if (X != Cmp.getOperand(0)) {
+ if (TrueIfSigned == FlipSign)
+ return new ICmpInst(ICmpInst::ICMP_SGT, X,
+ ConstantInt::getAllOnesValue(X->getType()));
+ return new ICmpInst(ICmpInst::ICMP_SLT, X,
+ ConstantInt::getNullValue(X->getType()));
+ }
+ }
+
if (auto *BO = dyn_cast<BinaryOperator>(Cmp.getOperand(0)))
if (Instruction *I = foldICmpBinOpWithConstant(Cmp, BO, *C))
return I;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index 5e0cd17fb1924..12a33e89bf040 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -812,6 +812,12 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
return takeLog2(Op, /*Depth=*/0, AssumeNonZero, /*DoFold=*/true);
return nullptr;
}
+
+ /// Try to strip off sign bit preserving/flipping operations.
+ /// The second return value indicates whether we should flip the sign bit
+ /// first.
+ std::pair<Value *, bool>
+ stripSignBitPreservingOrFlippingOperations(Value *X, unsigned Depth);
};
class Negator final {
>From 9611274e1089c8a02ff35fa1e1a899c0cf951af1 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 30 May 2025 16:08:33 +0800
Subject: [PATCH 2/2] [InstCombine] Remove one-use constraint
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c585b095b1ede..03db8fc5e1d1c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3512,7 +3512,7 @@ Instruction *InstCombinerImpl::foldICmpBitCast(ICmpInst &Cmp) {
std::pair<Value *, bool>
InstCombinerImpl::stripSignBitPreservingOrFlippingOperations(Value *X,
unsigned Depth) {
- if (!X->hasOneUse() || Depth++ >= MaxAnalysisRecursionDepth)
+ if (Depth++ >= MaxAnalysisRecursionDepth)
return {X, false};
auto FlipSign = [](std::pair<Value *, bool> P, bool Flip) {
More information about the llvm-commits
mailing list