[llvm] [InstCombine] Fold redundant select guards for ctpop (PR #195443)

Yunbo Ni via llvm-commits llvm-commits at lists.llvm.org
Sat May 2 05:46:43 PDT 2026


================
@@ -4317,6 +4317,26 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (Instruction *I = canonicalizeScalarSelectOfVecs(SI, *this))
     return I;
 
+  // Fold: select (icmp ult X, 2), X, ctpop(X)  -->  ctpop(X)
+  // Fold: select (icmp eq X, -1), BitWidth, ctpop(X)  -->  ctpop(X)
+  // ctpop(0)==0, ctpop(1)==1, ctpop(-1)==BitWidth, so guards are redundant.
+  {
+    Value *X;
+    CmpPredicate CtpopPred;
+    Value *CtpopCmpLHS, *CtpopCmpRHS;
+    unsigned CtpopBitWidth = SelType->getScalarSizeInBits();
+    if (match(FalseVal, m_Intrinsic<Intrinsic::ctpop>(m_Value(X))) &&
+        match(CondVal, m_ICmp(CtpopPred, m_Value(CtpopCmpLHS), m_Value(CtpopCmpRHS)))) {
+      if (CtpopCmpLHS == X && CtpopPred == ICmpInst::ICMP_ULT &&
+          match(CtpopCmpRHS, m_SpecificInt(2)) && TrueVal == X)
+        return replaceInstUsesWith(SI, FalseVal);
----------------
cardigan1008 wrote:

> Please call `dropPoisonGeneratingAnnotations` on ctpop and re-queue the instruction. See also `foldIsPowerOf2OrZero`.

Here is a related miscompilation case:

```llvm
declare i32 @llvm.ctpop.i32(i32)

declare void @use_noundef(i32 noundef)

define i32 @mut_allones_range_i32(i32 %x) {
  %cmp = icmp eq i32 %x, -1
  %pop = call range(i32 0, 32) i32 @llvm.ctpop.i32(i32 %x)
  %res = select i1 %cmp, i32 32, i32 %pop
  call void @use_noundef(i32 %res)
  ret i32 %res
}
```

Alive2 proof: https://alive2.llvm.org/ce/z/tpHsL8

> Found with [Archer](https://github.com/cuhk-s3/Archer). Please let me know if anything is wrong.


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


More information about the llvm-commits mailing list