https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82547

            Bug ID: 82547
           Summary: wide_int is not setting overflow properly for large
                    unsigned add/subtract calculations.
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: other
          Assignee: unassigned at gcc dot gnu.org
          Reporter: amacleod at redhat dot com
  Target Milestone: ---
            Target: x86_64-pc-linux-gnu

Created attachment 42364
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=42364&action=edit
patch which applied to wide-int.cc shows the bug in the selftests when the
compiler is built.

I ran into a bug when using a wide_int that is larger than HOST_WIDE_INT.

Using an unsigned 128 bit integer fails to set the overflow bit properly when
an underflow or overflow occurs in subtraction. I presume wi::add is the same.
the calculation is 

    0 - (MAXINT - 2) 

It produces the correct value, but does not set the overflow bit properly.

I notice all through the wide_int code 'overflow' is set differently depending
on whether  (sgn == SIGNED).  However, in wi::sub_large, it simply says:
 if (len * HOST_BITS_PER_WIDE_INT < prec)
    {
      val[len] = mask0 - mask1 - borrow;
      len++;
      if (overflow) 
        *overflow = false;
    }

just always sets it to false regardless of the values. It doesn't actually
check anything. 

Not sure how to reproduce it exactly, so I added some code to the wide_int
selftests which show the overflow bits as they are calculated for 32, 64 and
128 bit unsigned values.


Attached is a patch to wide-int.cc which performs the calculation in various
precisions.  It outputs the correct '1' for 32 and 64, but shows that overflow
is not set correctly for the 128 bit type.

output is:
32 bit  ov2 1
64 bit  ov2 1
128 bit ov2 0


ov2 should also be 1 in the final test for 128 bit.

Reply via email to