Skip to content

Commit

Permalink
[InstCombine] Simplify the pattern a ne/eq (zext/sext (a ne/eq c)) (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
dtcxzyw authored Oct 6, 2023
1 parent 0e099fa commit b3b3336
Show file tree
Hide file tree
Showing 2 changed files with 209 additions and 114 deletions.
67 changes: 67 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6481,6 +6481,73 @@ Instruction *InstCombinerImpl::foldICmpUsingBoolRange(ICmpInst &I) {
Y->getType()->isIntOrIntVectorTy(1) && Pred == ICmpInst::ICMP_ULE)
return BinaryOperator::CreateOr(Builder.CreateIsNull(X), Y);

// icmp eq/ne X, (zext/sext (icmp eq/ne X, C))
ICmpInst::Predicate Pred1, Pred2;
const APInt *C;
Instruction *ExtI;
if (match(&I, m_c_ICmp(Pred1, m_Value(X),
m_CombineAnd(m_Instruction(ExtI),
m_ZExtOrSExt(m_ICmp(Pred2, m_Deferred(X),
m_APInt(C)))))) &&
ICmpInst::isEquality(Pred1) && ICmpInst::isEquality(Pred2)) {
bool IsSExt = ExtI->getOpcode() == Instruction::SExt;
bool HasOneUse = ExtI->hasOneUse() && ExtI->getOperand(0)->hasOneUse();
auto CreateRangeCheck = [&] {
Value *CmpV1 =
Builder.CreateICmp(Pred1, X, Constant::getNullValue(X->getType()));
Value *CmpV2 = Builder.CreateICmp(
Pred1, X, ConstantInt::getSigned(X->getType(), IsSExt ? -1 : 1));
return BinaryOperator::Create(
Pred1 == ICmpInst::ICMP_EQ ? Instruction::Or : Instruction::And,
CmpV1, CmpV2);
};
if (C->isZero()) {
if (Pred2 == ICmpInst::ICMP_EQ) {
// icmp eq X, (zext/sext (icmp eq X, 0)) --> false
// icmp ne X, (zext/sext (icmp eq X, 0)) --> true
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
} else if (!IsSExt || HasOneUse) {
// icmp eq X, (zext (icmp ne X, 0)) --> X == 0 || X == 1
// icmp ne X, (zext (icmp ne X, 0)) --> X != 0 && X != 1
// icmp eq X, (sext (icmp ne X, 0)) --> X == 0 || X == -1
// icmp ne X, (sext (icmp ne X, 0)) --> X != 0 && X == -1
return CreateRangeCheck();
}
} else if (IsSExt ? C->isAllOnes() : C->isOne()) {
if (Pred2 == ICmpInst::ICMP_NE) {
// icmp eq X, (zext (icmp ne X, 1)) --> false
// icmp ne X, (zext (icmp ne X, 1)) --> true
// icmp eq X, (sext (icmp ne X, -1)) --> false
// icmp ne X, (sext (icmp ne X, -1)) --> true
return replaceInstUsesWith(
I, ConstantInt::getBool(I.getType(), Pred1 == ICmpInst::ICMP_NE));
} else if (!IsSExt || HasOneUse) {
// icmp eq X, (zext (icmp eq X, 1)) --> X == 0 || X == 1
// icmp ne X, (zext (icmp eq X, 1)) --> X != 0 && X != 1
// icmp eq X, (sext (icmp eq X, -1)) --> X == 0 || X == -1
// icmp ne X, (sext (icmp eq X, -1)) --> X != 0 && X == -1
return CreateRangeCheck();
}
} else {
// when C != 0 && C != 1:
// icmp eq X, (zext (icmp eq X, C)) --> icmp eq X, 0
// icmp eq X, (zext (icmp ne X, C)) --> icmp eq X, 1
// icmp ne X, (zext (icmp eq X, C)) --> icmp ne X, 0
// icmp ne X, (zext (icmp ne X, C)) --> icmp ne X, 1
// when C != 0 && C != -1:
// icmp eq X, (sext (icmp eq X, C)) --> icmp eq X, 0
// icmp eq X, (sext (icmp ne X, C)) --> icmp eq X, -1
// icmp ne X, (sext (icmp eq X, C)) --> icmp ne X, 0
// icmp ne X, (sext (icmp ne X, C)) --> icmp ne X, -1
return ICmpInst::Create(
Instruction::ICmp, Pred1, X,
ConstantInt::getSigned(X->getType(), Pred2 == ICmpInst::ICMP_NE
? (IsSExt ? -1 : 1)
: 0));
}
}

return nullptr;
}

Expand Down
Loading

0 comments on commit b3b3336

Please sign in to comment.