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
|
// 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;
|
||||||
}
|
}
|
||||||
|
16
cmThread.c
16
cmThread.c
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user