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 11 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
 
342
 
343
 //=================================================================
343
 //=================================================================
344
 // Floating point byte swapping
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
 unsigned           cmFfSwapFloatToUInt( float v )
362
 unsigned           cmFfSwapFloatToUInt( float v )
346
 {
363
 {
347
   assert( sizeof(float) == sizeof(unsigned));
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
 float              cmFfSwapUIntToFloat( unsigned v )
370
 float              cmFfSwapUIntToFloat( unsigned v )
352
 {
371
 {
353
   assert( sizeof(float) == sizeof(unsigned));
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
 unsigned long long cmFfSwapDoubleToULLong( double v )
379
 unsigned long long cmFfSwapDoubleToULLong( double v )
359
 {
380
 {
360
   assert( sizeof(double) == sizeof(unsigned long long));
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
 double             cmFfSwapULLongToDouble( unsigned long long v )
387
 double             cmFfSwapULLongToDouble( unsigned long long v )
365
 {
388
 {
366
   assert( sizeof(double) == sizeof(unsigned long long));
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
 #endif
1068
 #endif
1069
 
1069
 
1070
 #ifdef OS_LINUX
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
 #endif
1086
 #endif
1073
 }
1087
 }
1074
 
1088
 

Loading…
Cancel
Save