Re: [PATCH] Optimize a >= 0 && a < b if VR info says b >= 0 (PR tree-optimization/77664)
On Thu, 6 Oct 2016, Jakub Jelinek wrote: > Hi! > > For signed a, if we see a >= 0 && a < b and from VR know that b >= 0, > we can optimize those 2 comparisons into one unsigned - > (unsigned) a < (unsigned) b. Similarly for a < 0 || a > b (and also > for a <= b in the first and a >= b in the second). > > The patch implements it in the reassoc optimize_range_tests optimization, > so that it can handle even comparisons that aren't adjacent in the && or || > or & or | conditions, and can handle the conditions across multiple bbs as > well. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? Ok. Thanks, Richard. > 2016-10-06 Jakub Jelinek> > PR tree-optimization/77664 > * tree-ssa-reassoc.c (update_range_test): Also clear low and high > for the other ranges. > (optimize_range_tests_diff): Fix up formatting. > (optimize_range_tests_var_bound): New function. > (optimize_range_tests): Use it. > > * gcc.dg/tree-ssa/pr77664.c: New test. > * gcc.dg/pr77664.c: New test. > > --- gcc/tree-ssa-reassoc.c.jj 2016-10-05 17:01:28.724673717 +0200 > +++ gcc/tree-ssa-reassoc.c2016-10-06 13:34:08.872512318 +0200 > @@ -2428,6 +2428,8 @@ update_range_test (struct range_entry *r >else > oe->op = error_mark_node; >range->exp = NULL_TREE; > + range->low = NULL_TREE; > + range->high = NULL_TREE; > } >return true; > } > @@ -2485,10 +2487,10 @@ optimize_range_tests_xor (enum tree_code > ((X - 43U) & ~(75U - 43U)) <= 3U. */ > static bool > optimize_range_tests_diff (enum tree_code opcode, tree type, > - tree lowi, tree lowj, tree highi, tree highj, > - vec *ops, > - struct range_entry *rangei, > - struct range_entry *rangej) > +tree lowi, tree lowj, tree highi, tree highj, > +vec *ops, > +struct range_entry *rangei, > +struct range_entry *rangej) > { >tree tem1, tem2, mask; >/* Check highi - lowi == highj - lowj. */ > @@ -2829,6 +2831,197 @@ optimize_range_tests_to_bit_test (enum t >return any_changes; > } > > +/* Attempt to optimize for signed a and b where b is known to be >= 0: > + a >= 0 && a < b into (unsigned) a < (unsigned) b > + a >= 0 && a <= b into (unsigned) a <= (unsigned) b */ > + > +static bool > +optimize_range_tests_var_bound (enum tree_code opcode, int first, int length, > + vec *ops, > + struct range_entry *ranges) > +{ > + int i; > + bool any_changes = false; > + hash_map *map = NULL; > + > + for (i = first; i < length; i++) > +{ > + if (ranges[i].exp == NULL_TREE || !ranges[i].in_p) > + continue; > + > + tree type = TREE_TYPE (ranges[i].exp); > + if (!INTEGRAL_TYPE_P (type) > + || TYPE_UNSIGNED (type) > + || ranges[i].low == NULL_TREE > + || !integer_zerop (ranges[i].low) > + || ranges[i].high != NULL_TREE) > + continue; > + /* EXP >= 0 here. */ > + if (map == NULL) > + map = new hash_map ; > + map->put (ranges[i].exp, i); > +} > + > + if (map == NULL) > +return false; > + > + for (i = 0; i < length; i++) > +{ > + if (ranges[i].low == NULL_TREE > + || ranges[i].high == NULL_TREE > + || !integer_zerop (ranges[i].low) > + || !integer_zerop (ranges[i].high)) > + continue; > + > + gimple *stmt; > + tree_code ccode; > + tree rhs1, rhs2; > + if (ranges[i].exp) > + { > + stmt = SSA_NAME_DEF_STMT (ranges[i].exp); > + if (!is_gimple_assign (stmt)) > + continue; > + ccode = gimple_assign_rhs_code (stmt); > + rhs1 = gimple_assign_rhs1 (stmt); > + rhs2 = gimple_assign_rhs2 (stmt); > + } > + else > + { > + operand_entry *oe = (*ops)[ranges[i].idx]; > + stmt = last_stmt (BASIC_BLOCK_FOR_FN (cfun, oe->id)); > + if (gimple_code (stmt) != GIMPLE_COND) > + continue; > + ccode = gimple_cond_code (stmt); > + rhs1 = gimple_cond_lhs (stmt); > + rhs2 = gimple_cond_rhs (stmt); > + } > + > + if (TREE_CODE (rhs1) != SSA_NAME > + || rhs2 == NULL_TREE > + || TREE_CODE (rhs2) != SSA_NAME) > + continue; > + > + switch (ccode) > + { > + case GT_EXPR: > + case GE_EXPR: > + if (!ranges[i].in_p) > + std::swap (rhs1, rhs2); > + ccode = swap_tree_comparison (ccode); > + break; > + case LT_EXPR: > + case LE_EXPR: > + if (ranges[i].in_p) > + std::swap (rhs1, rhs2); > + break; > + default: > + continue; > + } > + > + int *idx = map->get (rhs1); > + if (idx == NULL) > + continue; > + > + wide_int nz = get_nonzero_bits (rhs2); > + if (wi::neg_p (nz)) > +
Re: [PATCH] Optimize a >= 0 && a < b if VR info says b >= 0 (PR tree-optimization/77664)
On Thu, Oct 06, 2016 at 11:55:00PM +0200, Marc Glisse wrote: > On Thu, 6 Oct 2016, Jakub Jelinek wrote: > > >For signed a, if we see a >= 0 && a < b and from VR know that b >= 0, > >we can optimize those 2 comparisons into one unsigned - > >(unsigned) a < (unsigned) b. Similarly for a < 0 || a > b (and also > >for a <= b in the first and a >= b in the second). > > I guess that the slightly more general: > X >= A && X < B where we know that A <= B > --> (unsigned)X - (unsigned)A < (unsigned)B - (unsigned)A > > generates too many operations and does not gain anything? Yeah, I think replacing 2 comparisons and one && with 2 subtractions and one comparison isn't a clear win. For constant A and B the reassoc optimize_range_tests of course handles it for a long time already. > The case where A > and B are constants seems to be handled by ifcombine, currently. Jakub
Re: [PATCH] Optimize a >= 0 && a < b if VR info says b >= 0 (PR tree-optimization/77664)
On Thu, 6 Oct 2016, Jakub Jelinek wrote: For signed a, if we see a >= 0 && a < b and from VR know that b >= 0, we can optimize those 2 comparisons into one unsigned - (unsigned) a < (unsigned) b. Similarly for a < 0 || a > b (and also for a <= b in the first and a >= b in the second). I guess that the slightly more general: X >= A && X < B where we know that A <= B --> (unsigned)X - (unsigned)A < (unsigned)B - (unsigned)A generates too many operations and does not gain anything? The case where A and B are constants seems to be handled by ifcombine, currently. -- Marc Glisse
[PATCH] Optimize a >= 0 && a < b if VR info says b >= 0 (PR tree-optimization/77664)
Hi! For signed a, if we see a >= 0 && a < b and from VR know that b >= 0, we can optimize those 2 comparisons into one unsigned - (unsigned) a < (unsigned) b. Similarly for a < 0 || a > b (and also for a <= b in the first and a >= b in the second). The patch implements it in the reassoc optimize_range_tests optimization, so that it can handle even comparisons that aren't adjacent in the && or || or & or | conditions, and can handle the conditions across multiple bbs as well. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2016-10-06 Jakub JelinekPR tree-optimization/77664 * tree-ssa-reassoc.c (update_range_test): Also clear low and high for the other ranges. (optimize_range_tests_diff): Fix up formatting. (optimize_range_tests_var_bound): New function. (optimize_range_tests): Use it. * gcc.dg/tree-ssa/pr77664.c: New test. * gcc.dg/pr77664.c: New test. --- gcc/tree-ssa-reassoc.c.jj 2016-10-05 17:01:28.724673717 +0200 +++ gcc/tree-ssa-reassoc.c 2016-10-06 13:34:08.872512318 +0200 @@ -2428,6 +2428,8 @@ update_range_test (struct range_entry *r else oe->op = error_mark_node; range->exp = NULL_TREE; + range->low = NULL_TREE; + range->high = NULL_TREE; } return true; } @@ -2485,10 +2487,10 @@ optimize_range_tests_xor (enum tree_code ((X - 43U) & ~(75U - 43U)) <= 3U. */ static bool optimize_range_tests_diff (enum tree_code opcode, tree type, - tree lowi, tree lowj, tree highi, tree highj, - vec *ops, - struct range_entry *rangei, - struct range_entry *rangej) + tree lowi, tree lowj, tree highi, tree highj, + vec *ops, + struct range_entry *rangei, + struct range_entry *rangej) { tree tem1, tem2, mask; /* Check highi - lowi == highj - lowj. */ @@ -2829,6 +2831,197 @@ optimize_range_tests_to_bit_test (enum t return any_changes; } +/* Attempt to optimize for signed a and b where b is known to be >= 0: + a >= 0 && a < b into (unsigned) a < (unsigned) b + a >= 0 && a <= b into (unsigned) a <= (unsigned) b */ + +static bool +optimize_range_tests_var_bound (enum tree_code opcode, int first, int length, + vec *ops, + struct range_entry *ranges) +{ + int i; + bool any_changes = false; + hash_map *map = NULL; + + for (i = first; i < length; i++) +{ + if (ranges[i].exp == NULL_TREE || !ranges[i].in_p) + continue; + + tree type = TREE_TYPE (ranges[i].exp); + if (!INTEGRAL_TYPE_P (type) + || TYPE_UNSIGNED (type) + || ranges[i].low == NULL_TREE + || !integer_zerop (ranges[i].low) + || ranges[i].high != NULL_TREE) + continue; + /* EXP >= 0 here. */ + if (map == NULL) + map = new hash_map ; + map->put (ranges[i].exp, i); +} + + if (map == NULL) +return false; + + for (i = 0; i < length; i++) +{ + if (ranges[i].low == NULL_TREE + || ranges[i].high == NULL_TREE + || !integer_zerop (ranges[i].low) + || !integer_zerop (ranges[i].high)) + continue; + + gimple *stmt; + tree_code ccode; + tree rhs1, rhs2; + if (ranges[i].exp) + { + stmt = SSA_NAME_DEF_STMT (ranges[i].exp); + if (!is_gimple_assign (stmt)) + continue; + ccode = gimple_assign_rhs_code (stmt); + rhs1 = gimple_assign_rhs1 (stmt); + rhs2 = gimple_assign_rhs2 (stmt); + } + else + { + operand_entry *oe = (*ops)[ranges[i].idx]; + stmt = last_stmt (BASIC_BLOCK_FOR_FN (cfun, oe->id)); + if (gimple_code (stmt) != GIMPLE_COND) + continue; + ccode = gimple_cond_code (stmt); + rhs1 = gimple_cond_lhs (stmt); + rhs2 = gimple_cond_rhs (stmt); + } + + if (TREE_CODE (rhs1) != SSA_NAME + || rhs2 == NULL_TREE + || TREE_CODE (rhs2) != SSA_NAME) + continue; + + switch (ccode) + { + case GT_EXPR: + case GE_EXPR: + if (!ranges[i].in_p) + std::swap (rhs1, rhs2); + ccode = swap_tree_comparison (ccode); + break; + case LT_EXPR: + case LE_EXPR: + if (ranges[i].in_p) + std::swap (rhs1, rhs2); + break; + default: + continue; + } + + int *idx = map->get (rhs1); + if (idx == NULL) + continue; + + wide_int nz = get_nonzero_bits (rhs2); + if (wi::neg_p (nz)) + continue; + + /* We have EXP < RHS2 or EXP <= RHS2 where EXP >= 0 +and RHS2 is known to be RHS2 >= 0. */ + tree utype = unsigned_type_for (TREE_TYPE (rhs1)); + + enum warn_strict_overflow_code wc =