public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* 3.3.2 mips/ppc compiler bug?
@ 2003-12-29 20:50 Martin Rivers
  2003-12-30  9:58 ` Falk Hueffner
  2003-12-31  1:08 ` Alan Modra
  0 siblings, 2 replies; 3+ messages in thread
From: Martin Rivers @ 2003-12-29 20:50 UTC (permalink / raw)
  To: gcc-bugs

[-- Attachment #1: Type: text/plain, Size: 1364 bytes --]

Attached is a small sample of code which I do not believe is generating correct
code with the 3.3.2 compiler for mips or ppc cross compilers.  I am currently
investigating migrating our software from 2.95.3 to 3.3.2 levels of the
compiler.  The cross compiler is hosted on a linux Redhat 8.0 x86 workstation.

The code is compiled with the options -O2 -S (and for mips -mips3).   What I
notice is that when the division approach is used to generate the x and y
values, the 2.95.3 compiler generates code which does the right thing (in my
opinion) whereas the 3.3.2 compiler for both ppc and mips effectively leaves the
value received as cmdxy as input and the value passed as y to subr2 identical
which I don't believe is right.  The value passed in as x using the division for
the 3.3.2 compiler also doesn't appear correct (again in my opinion).

If I change to use a right shift (rather than the division) both the 2.95.3 and
3.3.2 compilers generate correct code.

I realize this is somewhat screwy code interleaving shifts and divides (this is
inherited code).  However, it seems reasonable that the generation of the value
of y using the division approach should not result in the same value as cmdxy.

Thanks for your help either in fix for the compiler or else in helping me to
understand why the division approach leads to the identify for cmdxy and y.



[-- Attachment #2: blah.c --]
[-- Type: text/plain, Size: 682 bytes --]

#if defined( OKAY )

void subr2( char *, int, int, int, int, int );

struct blah
{
      int a;
};

void subr( char *dest, int cmdxy, struct blah *blah, int destw )
{
   int x, y, h, w;
   int hw = blah->a;

   x = ((cmdxy>>14)<<18)>>18;
   y = (cmdxy<<18)>>18;
   h = hw >> 16;
   w = hw & 0xffff;

   subr2( dest, x, y, destw, h, w );
}

#else


void subr2( char *, int, int, int, int, int );

struct blah
{
      int a;
};

void subr( char *dest, int cmdxy, struct blah *blah, int destw )
{
   int x, y, h, w;
   int hw = blah->a;

   x = ((cmdxy>>14)<<18)/(1<<18);
   y = (cmdxy<<18)/(1<<18);
   h = hw >> 16;
   w = hw & 0xffff;

   subr2( dest, x, y, destw, h, w );
}

#endif

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: 3.3.2 mips/ppc compiler bug?
  2003-12-29 20:50 3.3.2 mips/ppc compiler bug? Martin Rivers
@ 2003-12-30  9:58 ` Falk Hueffner
  2003-12-31  1:08 ` Alan Modra
  1 sibling, 0 replies; 3+ messages in thread
From: Falk Hueffner @ 2003-12-30  9:58 UTC (permalink / raw)
  To: Martin Rivers; +Cc: gcc-bugs

Martin Rivers <rivers@lexmark.com> writes:

> the 3.3.2 compiler for both ppc and mips effectively leaves the
> value received as cmdxy as input and the value passed as y to subr2
> identical which I don't believe is right.
>
> void subr( char *dest, int cmdxy, struct blah *blah, int destw )
> {
>    y = (cmdxy<<18)/(1<<18);

gcc is right, because y can only differ from cmdxy in case of
overflow, which is undefined for signed types. That this appears to
"work" for shift is an optimizer weakness (at least for C99).

-- 
	Falk


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: 3.3.2 mips/ppc compiler bug?
  2003-12-29 20:50 3.3.2 mips/ppc compiler bug? Martin Rivers
  2003-12-30  9:58 ` Falk Hueffner
@ 2003-12-31  1:08 ` Alan Modra
  1 sibling, 0 replies; 3+ messages in thread
From: Alan Modra @ 2003-12-31  1:08 UTC (permalink / raw)
  To: Martin Rivers; +Cc: gcc-bugs

On Mon, Dec 29, 2003 at 01:56:13PM -0500, Martin Rivers wrote:
> However, it seems reasonable that the generation of the value
> of y using the division approach should not result in the same value as cmdxy.

No.  Your problem is that the shift left operator for signed integers
does not have defined overflow semantics.  Thus for int x, x << n is
not necessarily truncated to an int when x << n appears in an
intermediate expression.

It so happens that gcc currently does truncate (x << n) >> n, but from
my reading of ISO/IEC 9899:1999 it would not need to, while
(x << n) / (1 << n) is not truncated.  You're relying on undefined
behaviour.

Note also that the shift right operator is also undefined on negative
signed values.  Most people don't seem to know that a shift right
may not propagate sign bits.  Unsigned values _do_ have defined
overflow semantics, so you should change your program to use unsigned
ints.  If you really need to handle negative values then sign
extend values using something like the following example for an
18 bit field:

 y = (((unsigned int) x & 0x3ffff) ^ 0x20000) - 0x20000;

-- 
Alan Modra
IBM OzLabs - Linux Technology Centre


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2003-12-30 22:19 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-29 20:50 3.3.2 mips/ppc compiler bug? Martin Rivers
2003-12-30  9:58 ` Falk Hueffner
2003-12-31  1:08 ` Alan Modra

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).