This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] for PR 26900


On Fri, 16 Feb 2007, Zdenek Dvorak wrote:

> Hello,
> 
> > > to get rid of the assumptions for # of iterations of the loop in this
> > > PR, we need to be able to fold expressions like
> > > 
> > > x <= y + 1 && x - 1 > y
> > > 
> > > to false (of course assuming that the arithmetics does not overflow,
> > > otherwise the conditions may be satisfied by x == INT_MIN).
> > > 
> > > Another class of comparisons that we currently do not simplify is
> > > 
> > > x > y + 10 && x > y + 20
> > > 
> > > which is equivalent to just x > y + 20.
> > > 
> > > Originally, I thought I might be able to rewrite the inequalities as x -
> > > y <= 1 && x - y > 1 and use fold_range_test (the transformation itself
> > > is invalid, since it may introduce overflows, but thought that as long
> > > as I am only interested in true/false return values, I won't mind).
> > > However, this transformation may break things -- x <= y + INT_MAX is a
> > > nontrivial inequality, while x - y <= INT_MAX is always true.
> > > 
> > > Therefore, I have written a separate functions to fold the pair of
> > > inequalities in two variables.
> > 
> > See below for comments.  I think the overall idea is sound, but I'm
> > worried we get some corner cases wrong.  For example we can fold
> > 
> >   i1 + 1 >= i0 && i0 - 1 > i1
> > 
> > to false only because we know that changing the second term to
> > i0 > i1 + 1 will not introduce overflow that was not there before.
> > As you are canonicalizing comparisons i1 + cst1 CMP i2 + cst2 to
> > i1 - i2 CMP cst2 - cst1 we seem to lose the information on which
> > overflows we had seen already and which not.  Can you convince me
> > that there are no corner cases we get wrong with your patch?
> 
> the transformation to i1 - i2 CMP cst2 - cst1 is interpreted as if
> performed in unbounded precision, i.e., with its mathematical meaning.
> Note that we check TREE_OVERFLOW everywhere, to ensure that the
> transformations are correct.

That didn't really answer my question - of course we can check if
cst2 - cst1 overflows.  But we cannot check if i1 - i2 overflows
(but we can assume that i1 + 1 and i0 - 1 do not overflow).  My question
is whether we use more than the assumptions we can derive from the
_original_ expressions about overflow in later transformations that lead
to the folding result?

> > > + /* Tries to determine with what sign a simple term X appears in TERM.  If it
> > > +    succeeds, *SIGN is set to true if the X appears positively and to false if
> > > +    it appears negated, and true is returned.  Otherwise, false is returned.  */
> > > + static bool
> > > + sign_of_subterm_1 (tree term, tree x, bool *sign)
> > > + {
> > ...
> > > + }
> > > + 
> > > + /* Tries to determine with what sign SUBTERM appears in TERM.  If it succeeds,
> > > +    *SIGN is set to true if the SUBTERM appears positively and to false if
> > > +    it appears negated, and true is returned.  Otherwise, false is returned.  */
> > > + 
> > > + static bool
> > > + sign_of_subterm (tree term, tree subterm, bool *sign)
> > > + {
> > ...
> > > + }
> > 
> > These functions sound too generic, as far as I can see they are
> > used to invert a - b to b - a if the other comparison looked like that.
> > Why not simply ...
> > 
> > > +   /* The comparison is now in shape XL cmp XR + *R.  Move both variable
> > > +      terms to the left-hand side.  */
> > > + 
> > > +   if (xr)
> > > +     {
> > > +       if (xl)
> > > + 	*l = fold_build2 (MINUS_EXPR, type, xl, xr);
> > > +       else
> > > + 	*l = fold_build1 (NEGATE_EXPR, type, xr);
> > > +     }
> > 
> > ... canonicalize based on the DECL_UID of xl/xr here?
> 
> because xl/xr do not have to be DECLs.

Even in the set of testcases you included?  I see that 
simplify_using_condition is using expand_simple_operations on the
comparisons, so it should be easy to construct a testcase that
excercises the more complex parts?

Did you check what is the compile-time impact of this patch?

> > > + 
> > > +   /* If the variable appears negated in VAR, negate the whole expression.  */
> > > +   if (sign_of_subterm (var, *l, &positive)
> > > +       && !positive)
> > > +     {
> > > +       *l = fold_build1 (NEGATE_EXPR, type, *l);
> > > +       *r = fold_unary (NEGATE_EXPR, type, *r);
> > > +       if (TREE_OVERFLOW (*r))
> > > + 	return false;
> > > +       *cmp = swap_tree_comparison (*cmp);
> > > +     }
> > > + 
> > > +   return true;
> > > + }
> > 
> > static bool
> > separate_term (tree term, tree *x, tree *cst)
> > {
> >   tree op0, op1, type = TREE_TYPE (term);
> > 
> >   *x = term;
> >   *cst = build_int_cst (type, 0);
> > 
> >   if (TREE_CODE (term) == PLUS_EXPR)
> >     {
> >       op0 = TREE_OPERAND (term, 0);
> >       op1 = TREE_OPERAND (term, 1);
> >       if (TREE_CODE (op1) == INTEGER_CST)
> >         {
> >           *x = op0;
> >           *cst = op1;
> >         }
> >       else
> >         {
> >           *x = term;
> >           *cst = build_int_cst (type, 0);
> >         }
> > 
> > Does this happen?  Why not
> > 
> > static void
> > separate_term (tree term, tree *x, tree *cst)
> > {
> >   if (TREE_CODE (term) == PLUS_EXPR)
> >       && TREE_CODE (TREE_OPERAND (term, 1)) == INTEGER_CST)
> >     {
> >       *x = TREE_OPERAND (term, 0);
> >       *cst = TREE_OPERAND (term, 1);
> >     }
> >   else
> >     {
> >       *x = term;
> >       *cst = build_int_cst (TREE_TYPE (term), 0);
> >     }
> > }
> > 
> > which always succeeds (we canonicalize x - cst to x + -cst if -cst does
> > not overflow).
> 
> because this does not handle the case cst - x.

Hm, right.

Richard.

-- 
Richard Guenther <rguenther@suse.de>
Novell / SUSE Labs


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]