diff options
author | Roger Sayle <roger@nextmovesoftware.com> | 2018-05-24 20:47:03 +0000 |
---|---|---|
committer | Jeff Law <law@gcc.gnu.org> | 2018-05-24 14:47:03 -0600 |
commit | ba6557e2686306942b157c3350e7497e551afb80 (patch) | |
tree | 4a8896b5cc8eb4200c03939215754c0b775e381e /gcc/fold-const.c | |
parent | 520fe2e324da4b1aa2c1fbac29741bd45afa98c1 (diff) | |
download | gcc-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.c | 68 |
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 { |