Browse Source

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.
master
kevin 10 years ago
parent
commit
beefa4ef42
2 changed files with 45 additions and 7 deletions
  1. 30
    6
      cmMath.c
  2. 15
    1
      cmThread.c

+ 30
- 6
cmMath.c View File

@@ -342,28 +342,52 @@ float    cmMidiToHz( unsigned midi )
342 342
 
343 343
 //=================================================================
344 344
 // Floating point byte swapping
345
+
346
+// Unions used to type-pun the swapping functions and thereby 
347
+// avoid strict aliasing problems with -O2.  Using unions for 
348
+// this purpose is apparently legal under C99 but not C++.
349
+
350
+typedef union
351
+{
352
+  unsigned u;
353
+  float    f;
354
+} _cmMathU_t;
355
+
356
+typedef union
357
+{
358
+  unsigned long long u;
359
+  double    f;
360
+} _cmMathUL_t;
361
+
345 362
 unsigned           cmFfSwapFloatToUInt( float v )
346 363
 {
347 364
   assert( sizeof(float) == sizeof(unsigned));
348
-  return cmSwap32(*(unsigned*)&v);
365
+  _cmMathU_t u;
366
+  u.f=v;
367
+  return cmSwap32(u.u);
349 368
 }
350 369
 
351 370
 float              cmFfSwapUIntToFloat( unsigned v )
352 371
 {
353 372
   assert( sizeof(float) == sizeof(unsigned));
354
-  v = cmSwap32(v);
355
-  return *((float*)&v);
373
+  _cmMathU_t u;
374
+
375
+  u.u = cmSwap32(v);
376
+  return u.f;
356 377
 }
357 378
 
358 379
 unsigned long long cmFfSwapDoubleToULLong( double v )
359 380
 {
360 381
   assert( sizeof(double) == sizeof(unsigned long long));
361
-  return cmSwap64(*(unsigned long long*)&v);
382
+  _cmMathUL_t u;
383
+  u.f = v;
384
+  return cmSwap64(u.u);
362 385
 }
363 386
 
364 387
 double             cmFfSwapULLongToDouble( unsigned long long v )
365 388
 {
366 389
   assert( sizeof(double) == sizeof(unsigned long long));
367
-  v = cmSwap64(v);
368
-  return *((double*)&v);
390
+  _cmMathUL_t u;
391
+  u.u = cmSwap64(v);
392
+  return u.f;
369 393
 }

+ 15
- 1
cmThread.c View File

@@ -1068,7 +1068,21 @@ bool     cmThFloatCAS( float*    addr, float    old, float    new )
1068 1068
 #endif
1069 1069
 
1070 1070
 #ifdef OS_LINUX
1071
-  return  __sync_bool_compare_and_swap((unsigned*)addr, *(unsigned*)(&old),*(unsigned*)(&new)); 
1071
+  // If we use pointer aliasing to pun the pointer types then it will violate the
1072
+  // strict pointer aliasing rules used by -O2. Instead we use this union
1073
+  // punning scheme which in theory should always work in C99 (although no C++).
1074
+
1075
+  typedef union 
1076
+  {
1077
+    unsigned* up;
1078
+    float*    fp;
1079
+  } u;
1080
+
1081
+  u u0,u1;
1082
+  u0.fp = &old;
1083
+  u1.fp = &new;
1084
+
1085
+  return  __sync_bool_compare_and_swap((unsigned*)addr,*u0.up,*u1.up); 
1072 1086
 #endif
1073 1087
 }
1074 1088
 

Loading…
Cancel
Save