[llvm] [InstCombine] Improve folding of `icmp pred (and X, Mask/~Mask), Y)` (PR #81562)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 12 22:06:46 PST 2024
================
@@ -4068,11 +4068,117 @@ Instruction *InstCombinerImpl::foldSelectICmp(ICmpInst::Predicate Pred,
return nullptr;
}
+// Returns whether 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;
+ 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:
+ if (match(V, m_Not(m_Value(X))))
+ return isMaskOrZero(X, !Not, Q, Depth);
+
+ // (X ^ (X - 1)) is a Mask
+ return !Not &&
+ 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:
----------------
dtcxzyw wrote:
All the following intrinsics are `nounwind`.
```suggestion
```
https://github.com/llvm/llvm-project/pull/81562
More information about the llvm-commits
mailing list