This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Byteswapping floating point types


On 07/14/2009 10:44 PM, Andrew Troschinetz wrote:
Hi all,

I'm having an argument about byteswapping floating point types and since
the argument is mainly concerning the behavior of the compiler (and in
this case of GCC specifically) I figure this list is a good place to ask
for information.

A co-worker has preposed this function (simplified here) for providing
byteswaping for both integral and floating point types.

template<class T>
T byteswap(T value)
{
T result;
size_t n = sizeof (T);
unsigned char* p = (unsigned char*) &value;
for (size_t i = 0; i < n; ++i)
((unsigned char*) &result)[i] = p[n - 1 - i];
return result;
}

Now, aside from the fact that this template is _too_ generic and accepts
things it really shouldn't, it does successfully byteswap both integral
and floating point types. I believe that manipulating the underlying
bytes of floating point values via access through unsigned char* should
be safe, as opposed to a methods of byteswaping by leveraging unions
which breaks aliasing rules.

Doing this with unions doesn't break aliasing rules on gcc.


But for floating point types doesn't this signature run the risk of the
compiler putting a byteswapped floating point value into an FPU
register, thus causing the data to be modified?

Why would it? Perhaps you're concerned that loading into a FPU register would convert a signaling NaN into a quiet NaN, or somesuch?

Testing with GCC 3.5.x to GCC 4.x has shown that this issue doesn't
surface unless you attempt some mathematical operation on the float
containing a byteswaped value. In other words:

// This works
float before = 50.125484;
float swapped = byteswap (before);
float after = byteswap (swapped);
assert (before == after);

// This fails
float before = 50.125484;
float swapped = byteswap (before);
swapped += 0;
float after = byteswap (swapped);
assert (before == after);

My concern is that the compiler is free to put floating point values
into FPU registers as it sees fit and relying on the compiler not doing
so is dangerous. He feels that my concern is misguided and if his
implementation of byteswap() doesn't work it's because the compiler is
broken or someone is trying to do something with byteswapped floating
point values that they shouldn't be doing.

You're in the realm of at best implementation-defined or at worst undefined behaviour. The CPUs I know are quite happy to do exact copies of memory via floating-point registers, and some versions of memcpy() make use of that. But in general it's not guaranteed.

Andrew.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]