diff options
author | Jakub Jelinek <jakub@redhat.com> | 2017-07-19 14:31:59 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2017-07-19 14:31:59 +0200 |
commit | 8d1628eb33d4f53832d6d4be2b0021353057a370 (patch) | |
tree | d094faeffd74258f4d93793acf99507d3bb801ad /gcc/match.pd | |
parent | 20deef65ae6058143c29199c1aab12d94e75181c (diff) | |
download | gcc-8d1628eb33d4f53832d6d4be2b0021353057a370.zip gcc-8d1628eb33d4f53832d6d4be2b0021353057a370.tar.gz gcc-8d1628eb33d4f53832d6d4be2b0021353057a370.tar.bz2 |
re PR tree-optimization/81346 (Missed constant propagation into comparison)
PR tree-optimization/81346
* fold-const.h (fold_div_compare, range_check_type): Declare.
* fold-const.c (range_check_type): New function.
(build_range_check): Use range_check_type.
(fold_div_compare): No longer static, rewritten into
a match.pd helper function.
(fold_comparison): Don't call fold_div_compare here.
* match.pd (X / C1 op C2): New optimization using fold_div_compare
as helper function.
* gcc.dg/tree-ssa/pr81346-1.c: New test.
* gcc.dg/tree-ssa/pr81346-2.c: New test.
* gcc.dg/tree-ssa/pr81346-3.c: New test.
* gcc.dg/tree-ssa/pr81346-4.c: New test.
* gcc.target/i386/umod-3.c: Hide comparison against 1 from the
compiler to avoid X / C1 op C2 optimization to trigger.
From-SVN: r250338
Diffstat (limited to 'gcc/match.pd')
-rw-r--r-- | gcc/match.pd | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/gcc/match.pd b/gcc/match.pd index 979085a..fe27093 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -1132,6 +1132,60 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (wi::gt_p(@2, 0, TYPE_SIGN (TREE_TYPE (@2)))) (cmp @0 @1)))) +/* X / C1 op C2 into a simple range test. */ +(for cmp (simple_comparison) + (simplify + (cmp (trunc_div:s @0 INTEGER_CST@1) INTEGER_CST@2) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && integer_nonzerop (@1) + && !TREE_OVERFLOW (@1) + && !TREE_OVERFLOW (@2)) + (with { tree lo, hi; bool neg_overflow; + enum tree_code code = fold_div_compare (cmp, @1, @2, &lo, &hi, + &neg_overflow); } + (switch + (if (code == LT_EXPR || code == GE_EXPR) + (if (TREE_OVERFLOW (lo)) + { build_int_cst (type, (code == LT_EXPR) ^ neg_overflow); } + (if (code == LT_EXPR) + (lt @0 { lo; }) + (ge @0 { lo; })))) + (if (code == LE_EXPR || code == GT_EXPR) + (if (TREE_OVERFLOW (hi)) + { build_int_cst (type, (code == LE_EXPR) ^ neg_overflow); } + (if (code == LE_EXPR) + (le @0 { hi; }) + (gt @0 { hi; })))) + (if (!lo && !hi) + { build_int_cst (type, code == NE_EXPR); }) + (if (code == EQ_EXPR && !hi) + (ge @0 { lo; })) + (if (code == EQ_EXPR && !lo) + (le @0 { hi; })) + (if (code == NE_EXPR && !hi) + (lt @0 { lo; })) + (if (code == NE_EXPR && !lo) + (gt @0 { hi; })) + (if (GENERIC) + { build_range_check (UNKNOWN_LOCATION, type, @0, code == EQ_EXPR, + lo, hi); }) + (with + { + tree etype = range_check_type (TREE_TYPE (@0)); + if (etype) + { + if (! TYPE_UNSIGNED (etype)) + etype = unsigned_type_for (etype); + hi = fold_convert (etype, hi); + lo = fold_convert (etype, lo); + hi = const_binop (MINUS_EXPR, etype, hi, lo); + } + } + (if (etype && hi && !TREE_OVERFLOW (hi)) + (if (code == EQ_EXPR) + (le (minus (convert:etype @0) { lo; }) { hi; }) + (gt (minus (convert:etype @0) { lo; }) { hi; }))))))))) + /* X + Z < Y + Z is the same as X < Y when there is no overflow. */ (for op (lt le ge gt) (simplify |