[llvm] [AggressiveInstCombine] POPCNT generation for bit-count pattern (PR #177109)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 11 09:01:24 PST 2026
================
@@ -372,6 +372,80 @@ static bool tryToRecognizePopCount(Instruction &I) {
return false;
}
+// Try to recognize below function as popcount intrinsic.
+// https://doc.lagout.org/security/Hackers%20Delight.pdf
+// Also used in TargetLowering::expandCTPOP().
+//
+// int popcount(unsigned int i) {
+// uWord = (uWord & 0x55555555) + ((uWord>>1) & 0x55555555);
+// uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333);
+// uWord = (uWord & 0x0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F);
+// uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF);
+// return (uWord & 0x0000FFFF) + (uWord>>16);
+// }
+static bool tryToRecognizePopCount1(Instruction &I) {
+ if (I.getOpcode() != Instruction::Add)
+ return false;
+
+ Type *Ty = I.getType();
+ if (!Ty->isIntOrIntVectorTy())
+ return false;
+
+ unsigned Len = Ty->getScalarSizeInBits();
+ if (!(Len <= 128 && Len > 8 && Len % 8 == 0))
+ return false;
+
+ APInt Mask55 = APInt::getSplat(Len, APInt(8, 0x55));
+ APInt Mask33 = APInt::getSplat(Len, APInt(8, 0x33));
+ Value *Op0 = I.getOperand(0);
+ Value *Op1 = I.getOperand(1);
+ Value *LShrOp0;
+ // Matching "(uWord & 0x0000FFFF) + (uWord>>16)".
+ if ((match(Op1, m_LShr(m_Value(LShrOp0), m_SpecificInt(16)))) &&
+ match(Op0, m_And(m_Deferred(LShrOp0), m_SpecificInt(31)))) {
+ Value *ShiftOp0;
+ // Matching "uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF);".
+ if (match(LShrOp0,
+ m_c_Add(m_And(m_LShr(m_Value(ShiftOp0), m_SpecificInt(8)),
+ m_SpecificInt(983055)),
+ m_And(m_Deferred(ShiftOp0), m_SpecificInt(983055))))) {
+ Value *ShiftOp1;
+ // Matching "uWord = (uWord & 0x0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F)".
+ if (match(
+ ShiftOp0,
+ m_c_Add(m_And(m_LShr(m_Value(ShiftOp1), m_SpecificInt(4)),
+ m_SpecificInt(117901063)),
+ m_And(m_Deferred(ShiftOp1), m_SpecificInt(117901063))))) {
+ Value *ShiftOp2;
+ // Matching "uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333)".
+ if (match(
+ ShiftOp1,
+ m_c_Add(m_And(m_LShr(m_Value(ShiftOp2), m_SpecificInt(2)),
+ m_SpecificInt(Mask33)),
+ m_And(m_Deferred(ShiftOp2), m_SpecificInt(Mask33))))) {
+ Value *ShiftOp3;
+ // Matching "uWord = (uWord & 0x55555555) + ((uWord>>1) &
+ // 0x55555555)".
+ if (match(ShiftOp2,
+ m_c_Add(
+ m_And(m_LShr(m_Value(ShiftOp3), m_SpecificInt(1)),
+ m_SpecificInt(Mask55)),
+ m_And(m_Deferred(ShiftOp3), m_SpecificInt(Mask55))))) {
+ LLVM_DEBUG(dbgs() << "Recognized popcount intrinsic\n");
+ IRBuilder<> Builder(&I);
+ I.replaceAllUsesWith(Builder.CreateIntrinsic(
+ Intrinsic::ctpop, I.getType(), {ShiftOp3}));
----------------
topperc wrote:
Will this code incorrectly generate an i64 popcount if all the math happens to use i64 types, but use 32 bit constants?
https://github.com/llvm/llvm-project/pull/177109
More information about the llvm-commits
mailing list