This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: signed is undefined and has been since 1992 (in GCC)
On Tue, Jun 28, 2005 at 10:23:51AM +0300, Michael Veksler wrote:
On Jun 28, 2005, at 1:12 AM, Gabriel Dos Reis wrote:
> > > So,
> > > please, do refrain from reasoning like "since we did X for Y and Y was
> > > undefined behaviour, we should do the same for Z." "Undefined
> > > behaviour" isn't a 0 or 1 thingy, even though it is about computers.
> > > You need to evaluate them on case-by-case basis.
Andrew Pinski wrote on 28/06/2005 08:34:25:
> Gaby, I am not sure you can do that in a reliable way. You may end up
> with different behavior of overflow in the following two cases:
> 1. for (int i = x ; i <= y ; ++i)
> {
> // this loop can be eliminated - overflow case (y == MAX_INT)
> // is undefined.
> q= s + 5; // moved outside the loop.
> }
> 2. a = b + c; // modulo
>
> If you treat overflow in case 1 differently than in case 2 then
> you get into many inconsistencies and corner cases.
In digital logic optimization we speak of "don't cares". This means
that we have certain input combinations that we don't care about, but
we must produce correct logic for all the cases that we do care about.
It's really just the same for producing a compiler that matches a spec:
We want to produce the cheapest possible circuit/program, by taking
maximal advantage of the degrees of freedom provided by the don't-cares.
Andrew, you're exactly right that we can't define the behavior in a
reliable way, and THAT IS EXACTLY THE POINT. We want to produce the
most efficient possible implementation for the cases that *are* defined,
and the behavior for the undefined cases naturally falls out of that.
You've actually given us an excellent example above.
Consider a processor whose integer addition instruction wraps. Then
the cheapest implementation for examples 1 and 2 above that cover the
defined cases is to eliminate the loop in case 1, and produce a modulo
result in case 2. You worried about interaction between the two
constructs. Consider
/* int a, b, c; */
if (b > 0) {
a = b + c;
int count;
for (int i = c; i <= a; i++)
count++;
some_func(count);
}
Since behavior on integer overflow is undefined, we can optimize assuming
that overflow has not occurred. Then a > c, so the for loop always
executes b+1 times, and we end up with
if (b > 0)
some_func(b+1);
Any attempt to assign meaning to integer overflow would prevent this
optimization.