diff --git a/cmMath.c b/cmMath.c index 71227f6..afec115 100644 --- a/cmMath.c +++ b/cmMath.c @@ -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; } diff --git a/cmThread.c b/cmThread.c index cb3108d..adbb75c 100644 --- a/cmThread.c +++ b/cmThread.c @@ -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 }