[llvm] [CodeGenPrepare] Unfold slow ctpop when used in power-of-two test (PR #102731)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 21 04:43:56 PDT 2025
================
@@ -1762,6 +1763,61 @@ bool CodeGenPrepare::combineToUSubWithOverflow(CmpInst *Cmp,
return true;
}
+// Decanonicalizes icmp+ctpop power-of-two test if ctpop is slow.
+bool CodeGenPrepare::unfoldPow2Test(CmpInst *Cmp) {
+ CmpPredicate Pred;
+ Value *X;
+ const APInt *C;
+
+ // (icmp (ctpop x), c)
+ if (!match(Cmp, m_ICmp(Pred, m_Intrinsic<Intrinsic::ctpop>(m_Value(X)),
+ m_APIntAllowPoison(C))))
+ return false;
+
+ // This transformation increases the number of instructions, don't do it if
+ // ctpop is fast.
+ Type *OpTy = X->getType();
+ if (TLI->isCtpopFast(TLI->getValueType(*DL, OpTy)))
+ return false;
+
+ // ctpop(x) u< 2 -> (x & (x - 1)) == 0
+ // ctpop(x) u> 1 -> (x & (x - 1)) != 0
+ // Also handles ctpop(x) == 1 and ctpop(x) != 1 if ctpop(x) is known non-zero.
+ if ((Pred == CmpInst::ICMP_ULT && *C == 2) ||
+ (Pred == CmpInst::ICMP_UGT && *C == 1) ||
+ (ICmpInst::isEquality(Pred) && *C == 1 &&
+ isKnownNonZero(Cmp->getOperand(0), *DL))) {
+ IRBuilder<> Builder(Cmp);
+ Value *Sub = Builder.CreateAdd(X, Constant::getAllOnesValue(OpTy));
+ Value *And = Builder.CreateAnd(X, Sub);
+ CmpInst::Predicate NewPred =
+ (Pred == CmpInst::ICMP_ULT || Pred == CmpInst::ICMP_EQ)
+ ? CmpInst::ICMP_EQ
+ : CmpInst::ICMP_NE;
+ Value *NewCmp =
+ Builder.CreateICmp(NewPred, And, ConstantInt::getNullValue(OpTy));
+ Cmp->replaceAllUsesWith(NewCmp);
+ RecursivelyDeleteTriviallyDeadInstructions(Cmp);
+ return true;
+ }
+
+ // ctpop(x) == 1 -> (x ^ (x - 1)) u> (x - 1)
+ // ctpop(x) != 1 -> (x ^ (x - 1)) u<= (x - 1)
+ if (ICmpInst::isEquality(Pred) && *C == 1) {
----------------
arsenm wrote:
Yes, I get handling the invert and non-inverted forms. But I mean these two blocks of conditions
https://github.com/llvm/llvm-project/pull/102731
More information about the llvm-commits
mailing list