The initial idea of this optimization was to reduce it to "X != 0",
checking for either X being an unsigned or a truncating conversion.
Then we discussed reducing it to "(X & -X) != 0" instead. This form
would avoid the potential trapping problems (like -ftrapv) that might
happen in case X is not an unsigned type.
Then, as suggested by Roger Sayle in bugzilla, we could reduce to just
"-X != 0". Keeping the negated value in the pattern preserves any trapping
or UBs to be handled by other match.pd patterns that are more able to do
the conversion to "X != 0" when applicable. This would also spare us from
a TYPE_UNSIGNED check.
PR tree-optimization/102486
gcc/ChangeLog:
* match.pd (`popcount (X & -X) -> -X != 0`): New pattern.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr102486.c: New test.
Signed-off-by: Daniel Barboza <daniel.barboza@oss.qualcomm.com>
(popcount:s @1))
(popcount (log2 @0 @1)))))
+/* popcount (X & -X) is -X != 0. */
+(simplify
+ (POPCOUNT (convert?@2 (bit_and:c @0 (negate@1 @0))))
+ (with { tree type0 = TREE_TYPE (@0);
+ tree type2 = TREE_TYPE (@2); }
+ (if (INTEGRAL_TYPE_P (type0)
+ && TYPE_PRECISION (type2) <= TYPE_PRECISION (type0))
+ /* Use an explicit bool conversion to avoid errors when the
+ POPCOUNT result is assigned to a type (e.g. int) that
+ will generate a "bogus comparison result type" error. */
+ (convert:type
+ (ne:boolean_type_node
+ (convert:type2 @1) { build_zero_cst (type2); })))))
+
#if GIMPLE
/* popcount(zext(X)) == popcount(X). */
(simplify
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+int f (unsigned y)
+{
+ return __builtin_popcount (y & -y);
+}
+
+int f2 (int y)
+{
+ return __builtin_popcount (y & -y);
+}
+
+/* { dg-final { scan-tree-dump-times "popcount" 0 "optimized" } } */