Mateusz Loskot | 1 Aug 2008 23:55
Gravatar

[GCC 4.3] Strange -O2 optimization issue

Hello,

I'm experiencing a strange problem while building a small program
using GCC 4.3.1 (Debian, Lenny) with -O2 optimization.
The program is a simple hash generator from 2D point,
using high and low word of a coordinate (object of double type).
I include a small test program [1]

Here are 3 test cases that differ in optimization flag only

$ g++ -W -Wall -o bar bar.cpp
$ ./bar
1073741824
1073741824
1073741824
1073741824
1073741824

$ g++ -O1 -W -Wall -o bar bar.cpp
$ ./bar
1073741824
1073741824
1073741824
1073741824
1073741824

$ g++ -O2 -W -Wall -o bar bar.cpp
$ ./bar
136623933
1073741824
(Continue reading)

Brian Dessent | 2 Aug 2008 02:11
Favicon

Re: [GCC 4.3] Strange -O2 optimization issue

Mateusz Loskot wrote:

> Why the first value printed is different (136623933) in the 3rd
> test case.

Your suspicion is correct, as this violates the ISO C aliasing rules:

> static unsigned long HashDouble(double* pdfVal)
> {
>      unsigned int* pnValue = (unsigned int*)pdfVal;

You're accessing a variable of type double through a pointer of type
unsigned int.  For the purposes of optimization the compiler is allowed
to assume that values of type double will only be accessed through
variables of type double, and thus it can assume that pdfVal and pnValue
can't refer to the same thing.  It may seem nonsensical in this instance
that it would assume that, but it's still legal for the compiler to do
so.  And being able to make this assumption allows for interesting
optimizations, for example consider something like:

typedef struct { int size; float *data; } foo;

void bar (foo *src, foo *dest)
{
  for (int i = 0; i < src->size; i++)
    dest->data[i] += src->data[i];
}

In this example all the stuff happening in the loop with the data arrays
involves floats so the compiler can prove to itself that src->size (an
(Continue reading)

Mateusz Loskot | 2 Aug 2008 04:14
Gravatar

Re: [GCC 4.3] Strange -O2 optimization issue

Brian Dessent wrote:
> Mateusz Loskot wrote:
> 
>> Why the first value printed is different (136623933) in the 3rd
>> test case.
> 
> Your suspicion is correct, as this violates the ISO C aliasing rules:

Brian,

Good to hear I was close ;-)

>> static unsigned long HashDouble(double* pdfVal)
>> {
>>      unsigned int* pnValue = (unsigned int*)pdfVal;
> 
> You're accessing a variable of type double through a pointer of type
> unsigned int.  For the purposes of optimization the compiler is allowed
> to assume that values of type double will only be accessed through
> variables of type double, and thus it can assume that pdfVal and pnValue
> can't refer to the same thing.  It may seem nonsensical in this instance
> that it would assume that, but it's still legal for the compiler to do
> so.  
 > [...]

Thank you very much for in-depth explanation of the problem.
It was greatly helpful.

> If you want to rewrite your code in a conformant way you can use a union
> or memcpy; or you can disable strict aliasing with
(Continue reading)


Gmane