aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorRoger Sayle <roger@nextmovesoftware.com>2018-05-24 20:47:03 +0000
committerJeff Law <law@gcc.gnu.org>2018-05-24 14:47:03 -0600
commitba6557e2686306942b157c3350e7497e551afb80 (patch)
tree4a8896b5cc8eb4200c03939215754c0b775e381e /gcc/fold-const.c
parent520fe2e324da4b1aa2c1fbac29741bd45afa98c1 (diff)
downloadgcc-ba6557e2686306942b157c3350e7497e551afb80.zip
gcc-ba6557e2686306942b157c3350e7497e551afb80.tar.gz
gcc-ba6557e2686306942b157c3350e7497e551afb80.tar.bz2
fold-const.c (tree_nonzero_bits): New function.
* fold-const.c (tree_nonzero_bits): New function. * fold-const.h (tree_nonzero_bits): Likewise. * match.pd (POPCOUNT): New patterns to fold BUILTIN_POPCOUNT and friends. POPCOUNT(x&1) => x&1, POPCOUNT(x)==0 => x==0, etc. * gcc.dg/fold-popcount-1.c: New testcase. * gcc.dg/fold-popcount-2.c: New testcase. * gcc.dg/fold-popcount-3.c: New testcase. * gcc.dg/fold-popcount-4.c: New testcase. From-SVN: r260689
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index dc27744..0f57f07 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -14571,6 +14571,74 @@ c_getstr (tree src, unsigned HOST_WIDE_INT *strlen)
return string + offset;
}
+/* Given a tree T, compute which bits in T may be nonzero. */
+
+wide_int
+tree_nonzero_bits (const_tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case INTEGER_CST:
+ return wi::to_wide (t);
+ case SSA_NAME:
+ return get_nonzero_bits (t);
+ case NON_LVALUE_EXPR:
+ case SAVE_EXPR:
+ return tree_nonzero_bits (TREE_OPERAND (t, 0));
+ case BIT_AND_EXPR:
+ return wi::bit_and (tree_nonzero_bits (TREE_OPERAND (t, 0)),
+ tree_nonzero_bits (TREE_OPERAND (t, 1)));
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ return wi::bit_or (tree_nonzero_bits (TREE_OPERAND (t, 0)),
+ tree_nonzero_bits (TREE_OPERAND (t, 1)));
+ case COND_EXPR:
+ return wi::bit_or (tree_nonzero_bits (TREE_OPERAND (t, 1)),
+ tree_nonzero_bits (TREE_OPERAND (t, 2)));
+ CASE_CONVERT:
+ return wide_int::from (tree_nonzero_bits (TREE_OPERAND (t, 0)),
+ TYPE_PRECISION (TREE_TYPE (t)),
+ TYPE_SIGN (TREE_TYPE (TREE_OPERAND (t, 0))));
+ case PLUS_EXPR:
+ if (INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ wide_int nzbits1 = tree_nonzero_bits (TREE_OPERAND (t, 0));
+ wide_int nzbits2 = tree_nonzero_bits (TREE_OPERAND (t, 1));
+ if (wi::bit_and (nzbits1, nzbits2) == 0)
+ return wi::bit_or (nzbits1, nzbits2);
+ }
+ break;
+ case LSHIFT_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
+ {
+ tree type = TREE_TYPE (t);
+ wide_int nzbits = tree_nonzero_bits (TREE_OPERAND (t, 0));
+ wide_int arg1 = wi::to_wide (TREE_OPERAND (t, 1),
+ TYPE_PRECISION (type));
+ return wi::neg_p (arg1)
+ ? wi::rshift (nzbits, -arg1, TYPE_SIGN (type))
+ : wi::lshift (nzbits, arg1);
+ }
+ break;
+ case RSHIFT_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
+ {
+ tree type = TREE_TYPE (t);
+ wide_int nzbits = tree_nonzero_bits (TREE_OPERAND (t, 0));
+ wide_int arg1 = wi::to_wide (TREE_OPERAND (t, 1),
+ TYPE_PRECISION (type));
+ return wi::neg_p (arg1)
+ ? wi::lshift (nzbits, -arg1)
+ : wi::rshift (nzbits, arg1, TYPE_SIGN (type));
+ }
+ break;
+ default:
+ break;
+ }
+
+ return wi::shwi (-1, TYPE_PRECISION (TREE_TYPE (t)));
+}
+
#if CHECKING_P
namespace selftest {