This is the mail archive of the gcc@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]

Bug in fold-const.c


unsigned short c = 0x8000;

main()
{
  if ((c-0x8000) < 0  || (c-0x8000) >0x7fff)
    abort();
}

When compiling this little testcase with any gcc version (2.95, 3.1...)
without optimization anything works fine. By turning on optimization
it will abort. I debugged it a bit and found out, that the bug is probably
in the function make_range in fold-const.c


Take a look in the following code from make_range line 3027:


        /* If we're converting from an unsigned to a signed type,
           we will be doing the comparison as unsigned.  The tests above
           have already verified that LOW and HIGH are both positive.

           So we have to make sure that the original unsigned value will
           be interpreted as positive.  */

-> (c-0x8000) < 0)
-> minus_expr exp is done integer signed mode, TREE_UNSIGNED (type) is true (type of c)
->n_low is 0x8000

        if (TREE_UNSIGNED (type) && ! TREE_UNSIGNED (TREE_TYPE (exp)))
          {
            tree equiv_type = type_for_mode (TYPE_MODE (type), 1);
            tree high_positive;

            /* A range without an upper bound is, naturally, unbounded.
             Since convert would have cropped a very large value, use
             the max value for the destination type.  */
            high_positive
            = TYPE_MAX_VALUE (equiv_type) ? TYPE_MAX_VALUE (equiv_type)
              : TYPE_MAX_VALUE (type);
-> high positive is 0xffff
            high_positive = fold (build (RSHIFT_EXPR, type,
                                 convert (type, high_positive),
                                 convert (type, integer_one_node)));
->high_posotive is converted to 0x7fff
            /* If the low bound is specified, "and" the range with the
             range for which the original unsigned value will be
             positive.  */
            if (low != 0)
            {
              if (! merge_ranges (&n_in_p, &n_low, &n_high,
                              1, n_low, n_high,
                              1, convert (type, integer_zero_node),
                              high_positive))
                break;

              in_p = (n_in_p == in_p);
            }
            else
            {
              /* Otherwise, "or" the range with the range of the input
                 that will be interpreted as negative.  */
              if (! merge_ranges (&n_in_p, &n_low, &n_high,
                              0, n_low, n_high,
                              1, convert (type, integer_zero_node),
                              high_positive))
                break;

              in_p = (in_p != n_in_p);
            }
->n_low is 0, n_high is 0,
 ->>> n_low should be 0x8000, n_high should be 0xffff
          }


My first guess to fix this would be to something like this

         if (TREE_PRECISION (type) >= TREE_PRECISION (TREE_TYPE (exp)))
            high_positive = fold (build (RSHIFT_EXPR, type,
                                 convert (type, high_positive),
                                 convert (type, integer_one_node)));


Mit freundlichem Gruß / Best regards,

Hartmut Penner
GCC for S/390 Development

Internet Mail Address : hpenner@de.ibm.com

Tel: (49)-7031-16-4364


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