[llvm] [AggressiveInstCombine] POPCNT generation for bit-count pattern (PR #177109)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 16 08:44:02 PDT 2026


================
@@ -372,6 +372,140 @@ 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 popcount32(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);
+// }
+// int popcount64(unsigned long i) {
+// uWord = (uWord & 0x5555555555555555) + ((uWord>>1) & 0x5555555555555555);
+// uWord = (uWord & 0x3333333333333333) + ((uWord>>2) & 0x3333333333333333);
+// uWord = (uWord & 0x0F0F0F0F0F0F0F0F) + ((uWord>>4) & 0x0F0F0F0F0F0F0F0F);
+// uWord = (uWord & 0x00FF00FF00FF00FF) + ((uWord>>8) & 0x00FF00FF00FF00FF);
+// return  (uWord & 0x0000FFFF0000FFFF) + ((uWord>>16) & 0x0000FFFF0000FFFF);
+// return  (uWord & 0x00000000FFFFFFFF) + (uWord>>32) & 0x00000000FFFFFFFF;
+// }
+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 <= 64 && Len > 8 && Len % 8 == 0))
+    return false;
+
+  APInt Mask55 = APInt::getSplat(Len, APInt(8, 0x55));
+  APInt Mask33 = APInt::getSplat(Len, APInt(8, 0x33));
+  APInt Mask0F = APInt::getSplat(Len, APInt(8, 0x0F));
+  APInt Mask00FF;
+  if (Len == 16) {
+    Mask00FF = APInt(16, 0x00FF);
+  } else {
+    Mask00FF = APInt::getSplat(Len, APInt(16, 0x00FF));
+  }
+  APInt Mask0000FFFF;
+  if (Len <= 32) {
+    Mask0000FFFF = APInt(32, 0x0000FFFF);
+  } else {
+    Mask0000FFFF = APInt::getSplat(Len, APInt(32, 0x0000FFFF));
+  }
+
+  APInt Mask64 = APInt(64, 0x00000000FFFFFFFF);
+  // Matching "(uWord & 0x00000000FFFFFFFF) + (uWord>>32)".
+  // OR
+  // Matching "(uWord & 0x00000000FFFFFFFF) + ((uWord>>32) &
+  // 0x00000000FFFFFFFF)".
+  Value *ShiftOp;
+  Value *Start = &I;
+  bool Is64 = false;
+  if (match(Start,
+            m_c_Add(m_And(m_LShr(m_Value(ShiftOp), m_SpecificInt(32)),
+                          m_SpecificInt(Mask64)),
+                    m_And(m_Deferred(ShiftOp), m_SpecificInt(Mask64)))) ||
+      match(Start,
+            m_c_Add(m_LShr(m_Value(ShiftOp), m_SpecificInt(32)),
+                    m_And(m_Deferred(ShiftOp), m_SpecificInt(Mask64))))) {
+    Start = ShiftOp;
+    Is64 = true;
+  }
+  Value *LShrOp0;
+  // Matching "(uWord & 0x0000FFFF) + (uWord>>16)".
+  // Matching "(uWord & 0x0000FFFF) + ((uWord>>16) & 0x0000FFFF)".
+  bool Test16 = match(
+      Start, m_c_Add(m_And(m_LShr(m_Value(LShrOp0), m_SpecificInt(16)),
+                           m_SpecificInt(Mask0000FFFF)),
+                     m_And(m_Deferred(LShrOp0), m_SpecificInt(Mask0000FFFF))));
+
+  bool Is32 = false;
+  if ((Is64 && Test16) ||
+      (!Is64 && Len == 32 &&
+       (Test16 ||
+        match(Start, m_c_Add(m_LShr(m_Value(LShrOp0), m_SpecificInt(16)),
+                             m_And(m_Deferred(LShrOp0),
+                                   m_SpecificInt(Mask0000FFFF))))))) {
+    Start = LShrOp0;
+    Is32 = true;
+  }
+  Value *ShiftOp0;
+  // Matching "uWord = (uWord & 0x00FF00FF) + ((uWord>>8) & 0x00FF00FF);".
+  // OR
+  // Matching "uWord = (uWord & 0x00FF00FF) + (uWord>>8) ;".
+  bool Test8 = match(
+      Start, m_c_Add(m_And(m_LShr(m_Value(ShiftOp0), m_SpecificInt(8)),
+                           m_SpecificInt(Mask00FF)),
+                     m_And(m_Deferred(ShiftOp0), m_SpecificInt(Mask00FF))));
+  if (!((Is32 && Test8) ||
+        (!Is32 && Len == 16 &&
+         (Test8 ||
+          match(Start, m_c_Add(m_LShr(m_Value(ShiftOp0), m_SpecificInt(8)),
+                               m_And(m_Deferred(ShiftOp0),
+                                     m_SpecificInt(Mask00FF)))))))) {
+    return false;
+  }
+
+  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(Mask0F)),
+                     m_And(m_Deferred(ShiftOp1), m_SpecificInt(Mask0F))))) {
+    return false;
+  }
+
+  Value *ShiftOp2;
+  // Matching "uWord = (uWord & 0x33333333) + ((uWord>>2) & 0x33333333)".
+  if (match(ShiftOp1,
----------------
topperc wrote:

Invert this condition and early exit.

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


More information about the llvm-commits mailing list