Skip to content

Commit b3b3336

Browse files
authored
[InstCombine] Simplify the pattern a ne/eq (zext/sext (a ne/eq c)) (#65852)
This patch folds the pattern `a ne/eq (zext/sext (a ne/eq c))` into a boolean constant or a compare. Clang vs GCC: https://godbolt.org/z/4ro817WE8 Proof for `zext`: https://alive2.llvm.org/ce/z/6z9NRF Proof for `sext`: https://alive2.llvm.org/ce/z/tv5wuE Fixes #65073.
1 parent 0e099fa commit b3b3336

File tree

2 files changed

+209
-114
lines changed

2 files changed

+209
-114
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6481,6 +6481,73 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
64816481
Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE)
64826482
return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y);
64836483

6484+
// icmp eq/ne X, (zext/sext (icmp eq/ne X, C))
6485+
ICmpInst::Predicate Pred1, Pred2;
6486+
const APInt *C;
6487+
Instruction *ExtI;
6488+
if (match(&I, m_c_ICmp(Pred1, m_Value(X),
6489+
m_CombineAnd(m_Instruction(ExtI),
6490+
m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
6491+
m_APInt(C)))))) &&
6492+
ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
6493+
bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
6494+
bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
6495+
auto CreateRangeCheck = [&] {
6496+
Value *CmpV1 =
6497+
Builder.CreateICmp(Pred1, X, Constant::getNullValue(X->getType()));
6498+
Value *CmpV2 = Builder.CreateICmp(
6499+
Pred1, X, ConstantInt::getSigned(X->getType(), IsSExt ? -1 : 1));
6500+
return BinaryOperator::Create(
6501+
Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
6502+
CmpV1, CmpV2);
6503+
};
6504+
if (C->isZero()) {
6505+
if (Pred2 == ICmpInst::ICMP_EQ) {
6506+
// icmp eq X, (zext/sext (icmp eq X, 0)) --> false
6507+
// icmp ne X, (zext/sext (icmp eq X, 0)) --> true
6508+
return replaceInstUsesWith(
6509+
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
6510+
} else if (!IsSExt || HasOneUse) {
6511+
// icmp eq X, (zext (icmp ne X, 0)) --> X == 0 || X == 1
6512+
// icmp ne X, (zext (icmp ne X, 0)) --> X != 0 && X != 1
6513+
// icmp eq X, (sext (icmp ne X, 0)) --> X == 0 || X == -1
6514+
// icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X == -1
6515+
return CreateRangeCheck();
6516+
}
6517+
} else if (IsSExt ? C->isAllOnes() : C->isOne()) {
6518+
if (Pred2 == ICmpInst::ICMP_NE) {
6519+
// icmp eq X, (zext (icmp ne X, 1)) --> false
6520+
// icmp ne X, (zext (icmp ne X, 1)) --> true
6521+
// icmp eq X, (sext (icmp ne X, -1)) --> false
6522+
// icmp ne X, (sext (icmp ne X, -1)) --> true
6523+
return replaceInstUsesWith(
6524+
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
6525+
} else if (!IsSExt || HasOneUse) {
6526+
// icmp eq X, (zext (icmp eq X, 1)) --> X == 0 || X == 1
6527+
// icmp ne X, (zext (icmp eq X, 1)) --> X != 0 && X != 1
6528+
// icmp eq X, (sext (icmp eq X, -1)) --> X == 0 || X == -1
6529+
// icmp ne X, (sext (icmp eq X, -1)) --> X != 0 && X == -1
6530+
return CreateRangeCheck();
6531+
}
6532+
} else {
6533+
// when C != 0 && C != 1:
6534+
// icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
6535+
// icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1
6536+
// icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
6537+
// icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
6538+
// when C != 0 && C != -1:
6539+
// icmp eq X, (sext (icmp eq X, C)) --> icmp eq X, 0
6540+
// icmp eq X, (sext (icmp ne X, C)) --> icmp eq X, -1
6541+
// icmp ne X, (sext (icmp eq X, C)) --> icmp ne X, 0
6542+
// icmp ne X, (sext (icmp ne X, C)) --> icmp ne X, -1
6543+
return ICmpInst::Create(
6544+
Instruction::ICmp, Pred1, X,
6545+
ConstantInt::getSigned(X->getType(), Pred2 == ICmpInst::ICMP_NE
6546+
? (IsSExt ? -1 : 1)
6547+
: 0));
6548+
}
6549+
}
6550+
64846551
return nullptr;
64856552
}
64866553

0 commit comments

Comments
 (0)