aboutsummaryrefslogtreecommitdiff
path: root/gcc/match.pd
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-07-19 14:31:59 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2017-07-19 14:31:59 +0200
commit8d1628eb33d4f53832d6d4be2b0021353057a370 (patch)
treed094faeffd74258f4d93793acf99507d3bb801ad /gcc/match.pd
parent20deef65ae6058143c29199c1aab12d94e75181c (diff)
downloadgcc-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.pd54
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