diff options
author | Yury Gribov <tetra2005@gmail.com> | 2017-06-13 11:13:52 +0000 |
---|---|---|
committer | Maxim Ostapenko <chefmax@gcc.gnu.org> | 2017-06-13 14:13:52 +0300 |
commit | 16842d34e7fceebcecc24910e9219a1581fffb32 (patch) | |
tree | b8dfa51c6b364f24b5de6aa6cf85779c233e4c24 /gcc/fold-const.c | |
parent | ba593ad58f849c711afc0f2255630757e020ccda (diff) | |
download | gcc-16842d34e7fceebcecc24910e9219a1581fffb32.zip gcc-16842d34e7fceebcecc24910e9219a1581fffb32.tar.gz gcc-16842d34e7fceebcecc24910e9219a1581fffb32.tar.bz2 |
re PR tree-optimization/67328 (range test rather than single bit test for code testing enum values)
2017-06-13 Yury Gribov <tetra2005@gmail.com>
gcc/
PR tree-optimization/67328
* fold-const.c (maskable_range_p): New function.
(build_range_check): Generate bittests if possible.
gcc/testsuite/
PR tree-optimization/67328
* c-c++-common/fold-masked-cmp-1.c: New test.
* c-c++-common/fold-masked-cmp-2.c: Likewise.
* gcc.dg/pr46309.c: Fix pattern.
* gcc.dg/pr46309-2.c: Likewise.
From-SVN: r249149
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index a6dd274..74bbdb0 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -4745,6 +4745,40 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh, *pin_p = in_p, *plow = low, *phigh = high; return exp; } + +/* Returns TRUE if [LOW, HIGH] range check can be optimized to + a bitwise check i.e. when + LOW == 0xXX...X00...0 + HIGH == 0xXX...X11...1 + Return corresponding mask in MASK and stem in VALUE. */ + +static bool +maskable_range_p (const_tree low, const_tree high, tree type, tree *mask, + tree *value) +{ + if (TREE_CODE (low) != INTEGER_CST + || TREE_CODE (high) != INTEGER_CST) + return false; + + unsigned prec = TYPE_PRECISION (type); + wide_int lo = wi::to_wide (low, prec); + wide_int hi = wi::to_wide (high, prec); + + wide_int end_mask = lo ^ hi; + if ((end_mask & (end_mask + 1)) != 0 + || (lo & end_mask) != 0) + return false; + + wide_int stem_mask = ~end_mask; + wide_int stem = lo & stem_mask; + if (stem != (hi & stem_mask)) + return false; + + *mask = wide_int_to_tree (type, stem_mask); + *value = wide_int_to_tree (type, stem); + + return true; +} /* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result type, TYPE, return an expression to test if EXP is in (or out of, depending @@ -4754,7 +4788,7 @@ tree build_range_check (location_t loc, tree type, tree exp, int in_p, tree low, tree high) { - tree etype = TREE_TYPE (exp), value; + tree etype = TREE_TYPE (exp), mask, value; /* Disable this optimization for function pointer expressions on targets that require function pointer canonicalization. */ @@ -4787,6 +4821,13 @@ build_range_check (location_t loc, tree type, tree exp, int in_p, return fold_build2_loc (loc, EQ_EXPR, type, exp, fold_convert_loc (loc, etype, low)); + if (TREE_CODE (exp) == BIT_AND_EXPR + && maskable_range_p (low, high, etype, &mask, &value)) + return fold_build2_loc (loc, EQ_EXPR, type, + fold_build2_loc (loc, BIT_AND_EXPR, etype, + exp, mask), + value); + if (integer_zerop (low)) { if (! TYPE_UNSIGNED (etype)) |