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
// 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 )
{
assert( sizeof(float) == sizeof(unsigned));
return cmSwap32(*(unsigned*)&v);
_cmMathU_t u;
u.f=v;
return cmSwap32(u.u);
}
float cmFfSwapUIntToFloat( unsigned v )
{
assert( sizeof(float) == sizeof(unsigned));
v = cmSwap32(v);
return *((float*)&v);
_cmMathU_t u;
u.u = cmSwap32(v);
return u.f;
}
unsigned long long cmFfSwapDoubleToULLong( double v )
{
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 )
{
assert( sizeof(double) == sizeof(unsigned long long));
v = cmSwap64(v);
return *((double*)&v);
_cmMathUL_t u;
u.u = cmSwap64(v);
return u.f;
}

View File

@ -1068,7 +1068,21 @@ bool cmThFloatCAS( float* addr, float old, float new )
#endif
#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
}