+/* Return an expression that computes the popcount of src. */
+
+static tree
+build_popcount_expr (tree src)
+{
+ tree fn;
+ int prec = TYPE_PRECISION (TREE_TYPE (src));
+ int i_prec = TYPE_PRECISION (integer_type_node);
+ int li_prec = TYPE_PRECISION (long_integer_type_node);
+ int lli_prec = TYPE_PRECISION (long_long_integer_type_node);
+ if (prec <= i_prec)
+ fn = builtin_decl_implicit (BUILT_IN_POPCOUNT);
+ else if (prec == li_prec)
+ fn = builtin_decl_implicit (BUILT_IN_POPCOUNTL);
+ else if (prec == lli_prec || prec == 2 * lli_prec)
+ fn = builtin_decl_implicit (BUILT_IN_POPCOUNTLL);
+ else
+ return NULL_TREE;
+
+ tree utype = unsigned_type_for (TREE_TYPE (src));
+ src = fold_convert (utype, src);
+ if (prec < i_prec)
+ src = fold_convert (unsigned_type_node, src);
+ tree call;
+ if (prec == 2 * lli_prec)
+ {
+ tree src1 = fold_convert (long_long_unsigned_type_node,
+ fold_build2 (RSHIFT_EXPR, TREE_TYPE (src),
+ unshare_expr (src),
+ build_int_cst (integer_type_node,
+ lli_prec)));
+ tree src2 = fold_convert (long_long_unsigned_type_node, src);
+ tree call1 = build_call_expr (fn, 1, src1);
+ tree call2 = build_call_expr (fn, 1, src2);
+ call = fold_build2 (PLUS_EXPR, integer_type_node, call1, call2);
+ }
+ else
+ call = build_call_expr (fn, 1, src);
+
+ return call;
+}
+