cmMath.c, cmThread.c : Replaced type casting with use of unions to do type conversion in byte swap and CAS functions.

This was required to address a strict-aliasing violation in the release build.
This commit is contained in:
kevin 2013-12-12 12:19:52 -05:00
parent c442830e85
commit beefa4ef42
2 changed files with 45 additions and 7 deletions

View File

@ -342,28 +342,52 @@ float cmMidiToHz( unsigned midi )
//================================================================= //=================================================================
// Floating point byte swapping // Floating point byte swapping
// Unions used to type-pun the swapping functions and thereby
// avoid strict aliasing problems with -O2. Using unions for
// this purpose is apparently legal under C99 but not C++.
typedef union
{
unsigned u;
float f;
} _cmMathU_t;
typedef union
{
unsigned long long u;
double f;
} _cmMathUL_t;
unsigned cmFfSwapFloatToUInt( float v ) unsigned cmFfSwapFloatToUInt( float v )
{ {
assert( sizeof(float) == sizeof(unsigned)); assert( sizeof(float) == sizeof(unsigned));
return cmSwap32(*(unsigned*)&v); _cmMathU_t u;
u.f=v;
return cmSwap32(u.u);
} }
float cmFfSwapUIntToFloat( unsigned v ) float cmFfSwapUIntToFloat( unsigned v )
{ {
assert( sizeof(float) == sizeof(unsigned)); assert( sizeof(float) == sizeof(unsigned));
v = cmSwap32(v); _cmMathU_t u;
return *((float*)&v);
u.u = cmSwap32(v);
return u.f;
} }
unsigned long long cmFfSwapDoubleToULLong( double v ) unsigned long long cmFfSwapDoubleToULLong( double v )
{ {
assert( sizeof(double) == sizeof(unsigned long long)); assert( sizeof(double) == sizeof(unsigned long long));
return cmSwap64(*(unsigned long long*)&v); _cmMathUL_t u;
u.f = v;
return cmSwap64(u.u);
} }
double cmFfSwapULLongToDouble( unsigned long long v ) double cmFfSwapULLongToDouble( unsigned long long v )
{ {
assert( sizeof(double) == sizeof(unsigned long long)); assert( sizeof(double) == sizeof(unsigned long long));
v = cmSwap64(v); _cmMathUL_t u;
return *((double*)&v); u.u = cmSwap64(v);
return u.f;
} }

View File

@ -1068,7 +1068,21 @@ bool cmThFloatCAS( float* addr, float old, float new )
#endif #endif
#ifdef OS_LINUX #ifdef OS_LINUX
return __sync_bool_compare_and_swap((unsigned*)addr, *(unsigned*)(&old),*(unsigned*)(&new)); // If we use pointer aliasing to pun the pointer types then it will violate the
// strict pointer aliasing rules used by -O2. Instead we use this union
// punning scheme which in theory should always work in C99 (although no C++).
typedef union
{
unsigned* up;
float* fp;
} u;
u u0,u1;
u0.fp = &old;
u1.fp = &new;
return __sync_bool_compare_and_swap((unsigned*)addr,*u0.up,*u1.up);
#endif #endif
} }