[llvm] [CodeGenPrepare] Unfold slow ctpop when used in power-of-two test (PR #102731)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 12 00:20:35 PDT 2024


================
@@ -1757,6 +1758,40 @@ bool CodeGenPrepare::combineToUSubWithOverflow(CmpInst *Cmp,
   return true;
 }
 
+// Decanonicalizes icmp+ctpop power-of-two test if ctpop is slow.
+bool CodeGenPrepare::unfoldPow2Test(CmpInst *Cmp) {
+  ICmpInst::Predicate Pred;
+  Value *X;
+  uint64_t C;
+
+  if (!match(Cmp, m_ICmp(Pred, m_Intrinsic<Intrinsic::ctpop>(m_Value(X)),
+                         m_ConstantInt(C))))
+    return false;
+
+  Type *Ty = X->getType();
+  if (Ty->isVectorTy() || TTI->getPopcntSupport(Ty->getIntegerBitWidth()) ==
+                              TargetTransformInfo::PSK_FastHardware)
+    return false;
+
+  // (ctpop x) u< 2 -> (x & (x - 1)) == 0
+  // (ctpop x) u> 1 -> (x & (x - 1)) != 0
+  if ((Pred == CmpInst::ICMP_ULT && C == 2) ||
+      (Pred == CmpInst::ICMP_UGT && C == 1)) {
+    IRBuilder<> Builder(Cmp);
+    Value *Sub = Builder.CreateAdd(X, Constant::getAllOnesValue(Ty));
+    Value *And = Builder.CreateAnd(X, Sub);
+    CmpInst::Predicate NewPred =
+        Pred == CmpInst::ICMP_ULT ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
+    Value *NewCmp =
+        Builder.CreateICmp(NewPred, And, ConstantInt::getNullValue(Ty));
+    Cmp->replaceAllUsesWith(NewCmp);
+    RecursivelyDeleteTriviallyDeadInstructions(Cmp);
+    return true;
----------------
nikic wrote:

Can you please add an alive2 proof for the expansion? This probably needs freeze due to use duplication.

https://github.com/llvm/llvm-project/pull/102731


More information about the llvm-commits mailing list