Re: Recent change in tcp_output.c is surely wrong

From: Rogier Wolff (R.E.Wolff@BitWizard.nl)
Date: Tue Jan 18 2000 - 05:38:14 EST


Jamie Lokier wrote:
> Rogier Wolff wrote:
> > On the other hand, having thousands "silent departures from ANSI-C"
> > scattered through the kernel is not a good idea. I'm fine with having
> > a few __asm__ thingies that generate errors while compiling/linking.
> >
> > Someone is eventually going to have to port Linux to an architecture
> > that doesn't have a gcc port yet.
>
> It breaks with GCC too. How obvious do I have to be?
>
> #include <stdio.h>
> int main ()
> {
> unsigned short a = 0xffff;
> a = (a << 1) >> 1;
> printf ("a = 0x%x\n", (unsigned) a);
> return 0;
> }
>
> $ gcc -o test test.c
> $ ./test
> a = 0xffff

More reason, that IF you find the performance impact high enough, you
should do it with a macro, that can be changed to adopt to the
currrent status of compiler, length of types etc etc.

>
> --> high bit /not/ cleared
>
> > Oh, by the way, ANSI defines the behaviour as undefined, as a compiler
> > is allowed to recognize that (var <<1) >> 1 evaluates to "var" if done
> > with arbitrary precision.
>
> No. For any unsigned type as wide or wider than `unsigned int', that
> will clear the top bits. For narrower unsigned types it won't. For
> signed types it is implementation defined.

Hmm. I'm not too familiar with the exact wording of ANSI. However,
they usually take the road where "more accuracy in intermediates is
allowed", as that can normally only reduce the amount of trouble that
you get into when things near the limit of the size you're using.

> > for example
> >
> > array [index>>4].firstbyte = 0;
> >
> > could evaluate (the element size of array happens to be 16 bytes!)
> >
> > * (char *)array + (index & ~0xf) = 0;
> >
> > See, the compiler recognized that two shifts over the same width are
> > the same.
>
> Your example is wrong. You've shown `(a >> 4) << 4', which is obviously
> equal to `a & ~0xf' for any type :-)

Is a compiler allowed to optimize

    a + 4 - 4

into "a"?

There are "opposites" that can be taken together. So in principle:

        (a >> 4) << 4 == a

except that a few bits fall off at the binary point.

Similarly we agree that

        (a << 4) >> 4 == a

except that a few bits fall off at the high end. However, that's (as
you've demonstrated) dependent on the size of the intermediates
involved.

If you're right that a compiler may not extend the size of the
intermediates beyond the size of an unsiged int, the Alpha compiler
is in trouble, as it has to explicitly cater for this. Ints on Alpha
are 32 bits, but registers are 64 bits, so it will have to explicitly
clip the intermediate on:

        (a << 4) >> 4

Usually, ANSI will take the road where the compiler writer is allowed
to optimize for the common case: More accuracy usually doesn't matter.

                                Roger.

-- 
** R.E.Wolff@BitWizard.nl ** http://www.BitWizard.nl/ ** +31-15-2137555 **
*-- BitWizard writes Linux device drivers for any device you may have! --*
 "I didn't say it was your fault. I said I was going to blame it on you."

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Jan 23 2000 - 21:00:17 EST