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:
parent
c442830e85
commit
beefa4ef42
36
cmMath.c
36
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;
|
||||
}
|
||||
|
16
cmThread.c
16
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user