summaryrefslogtreecommitdiff
path: root/gcc/match.pd
diff options
context:
space:
mode:
authorMarc Glisse <marc.glisse@inria.fr>2019-05-31 18:54:30 +0200
committerMarc Glisse <glisse@gcc.gnu.org>2019-05-31 16:54:30 +0000
commit9cf60d3b0d793fbd3b97aa0163b44a5c0c4e9aa3 (patch)
tree79fec5f3316ae1b6c21485ab9aae4b5626f85b66 /gcc/match.pd
parentf4fde1b378ad68fb2dec6719ed26c1b901488e03 (diff)
Simplify more EXACT_DIV_EXPR comparisons
2019-05-31 Marc Glisse <marc.glisse@inria.fr> gcc/ * match.pd (X/[ex]D<Y/[ex]D): Handle negative denominator. ((size_t)(A /[ex] B) CMP C): New transformation. gcc/testsuite/ * gcc.dg/tree-ssa/cmpexactdiv-3.c: New file. * gcc.dg/tree-ssa/cmpexactdiv-4.c: New file. * gcc.dg/Walloca-13.c: Xfail. From-SVN: r271816
Diffstat (limited to 'gcc/match.pd')
-rw-r--r--gcc/match.pd31
1 files changed, 30 insertions, 1 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index e1fa75cf5a0..99ffb16c872 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1497,7 +1497,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(cmp (exact_div @0 INTEGER_CST@2) (exact_div @1 @2))
(if (wi::gt_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2))))
- (cmp @0 @1))))
+ (cmp @0 @1)
+ (if (wi::lt_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2))))
+ (cmp @1 @0)))))
/* X / C1 op C2 into a simple range test. */
(for cmp (simple_comparison)
@@ -3633,6 +3635,33 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
!= (cmp == LT_EXPR || cmp == LE_EXPR), type); }
(cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))
+/* Fold (size_t)(A /[ex] B) CMP C to (size_t)A CMP (size_t)B * C or A CMP' 0.
+
+ For small C (less than max/B), this is (size_t)A CMP (size_t)B * C.
+ For large C (more than min/B+2^size), this is also true, with the
+ multiplication computed modulo 2^size.
+ For intermediate C, this just tests the sign of A. */
+(for cmp (lt le gt ge)
+ cmp2 (ge ge lt lt)
+ (simplify
+ (cmp (convert (exact_div @0 INTEGER_CST@1)) INTEGER_CST@2)
+ (if (tree_nop_conversion_p (TREE_TYPE (@0), TREE_TYPE (@2))
+ && TYPE_UNSIGNED (TREE_TYPE (@2)) && !TYPE_UNSIGNED (TREE_TYPE (@0))
+ && wi::gt_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1))))
+ (with
+ {
+ tree utype = TREE_TYPE (@2);
+ wide_int denom = wi::to_wide (@1);
+ wide_int right = wi::to_wide (@2);
+ wide_int smax = wi::sdiv_trunc (wi::max_value (TREE_TYPE (@0)), denom);
+ wide_int smin = wi::sdiv_trunc (wi::min_value (TREE_TYPE (@0)), denom);
+ bool small = wi::leu_p (right, smax);
+ bool large = wi::geu_p (right, smin);
+ }
+ (if (small || large)
+ (cmp (convert:utype @0) (mult @2 (convert @1)))
+ (cmp2 @0 { build_zero_cst (TREE_TYPE (@0)); }))))))
+
/* Unordered tests if either argument is a NaN. */
(simplify
(bit_ior (unordered @0 @0) (unordered @1 @1))