[MLton-commit] r5525

Matthew Fluet fluet at mlton.org
Sat Apr 14 11:53:22 PDT 2007


Fixed aliasing problems with basis/Real/*.c files
----------------------------------------------------------------------

U   mlton/branches/on-20050822-x86_64-branch/runtime/Makefile
U   mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/class.c
U   mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/gdtoa.c
U   mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/signBit.c

----------------------------------------------------------------------

Modified: mlton/branches/on-20050822-x86_64-branch/runtime/Makefile
===================================================================
--- mlton/branches/on-20050822-x86_64-branch/runtime/Makefile	2007-04-13 23:20:47 UTC (rev 5524)
+++ mlton/branches/on-20050822-x86_64-branch/runtime/Makefile	2007-04-14 18:53:21 UTC (rev 5525)
@@ -189,14 +189,8 @@
 	basis-ffi.h						\
 	$(shell find basis -type f | grep '\.h$$')
 BASISCFILES :=							\
-	$(shell find basis -type f | grep '\.c$$' | grep -v Real/)
-# REAL_BASISCFILES is for files that we don't want compiled in the
-# big lump when compiling COMPILE_FAST.
-# Real/*.c can't be there because gcc -O2 messes some of them up.
-REAL_BASISCFILES :=						\
-	$(shell find basis -type f | grep '\.c$$' | grep Real/)
+	$(shell find basis -type f | grep '\.c$$')
 
-
 HFILES :=							\
 	cenv.h							\
 	$(UTILHFILES)						\
@@ -223,15 +217,13 @@
 endif
 
 ifeq ($(COMPILE_FAST), yes)
-  OBJS += basis.o basis/Real/real-basis.o
-  DEBUG_OBJS += basis-gdb.o basis/Real/real-basis-gdb.o
+  OBJS += basis.o
+  DEBUG_OBJS += basis-gdb.o
 else
   OBJS += 							\
-	$(foreach f, $(basename $(BASISCFILES)), $(f).o)	\
-	$(foreach f, $(basename $(REAL_BASISCFILES)), $(f).o)
+	$(foreach f, $(basename $(BASISCFILES)), $(f).o)
   DEBUG_OBJS += 						\
-	$(foreach f, $(basename $(BASISCFILES)), $(f)-gdb.o)	\
-	$(foreach f, $(basename $(REAL_BASISCFILES)), $(f)-gdb.o)
+	$(foreach f, $(basename $(BASISCFILES)), $(f)-gdb.o)
 endif
 
 ALL := libgdtoa.a libmlton.a libmlton-gdb.a
@@ -274,10 +266,6 @@
 	rm -f basis.c
 	cat $(BASISCFILES) >> basis.c
 
-basis/Real/real-basis.c: $(REAL_BASISCFILES)
-	rm -f basis/Real/real-basis.c
-	cat $(REAL_BASISCFILES) >> basis/Real/real-basis.c
-
 gen/c-types.h gen/c-types.sml gen/ml-types.h: gen/gen-types.c util.h util.o
 	$(CC) $(OPTCFLAGS) $(WARNCFLAGS) -o gen/gen-types gen/gen-types.c util.o
 	rm -f gen/c-types.h gen/c-types.sml gen/ml-types.h
@@ -330,17 +318,6 @@
 basis.o: basis.c $(BASISCFILES) $(HFILES)
 	$(CC) -Ibasis -Ibasis/Word -Ibasis/Real $(OPTCFLAGS) $(OPTWARNCFLAGS) -Wno-redundant-decls -c -o $@ $<
 
-# It looks like we don't follow the C spec w.r.t. aliasing.  And gcc
-# -O2 catches us on the code in Real/*.c where we treat a double as a
-# chunk of two words.  Files that have been known to cause problems
-# are class.c and gdtoa.c.  But there may be others.  So, we compile
-# with -fno-strict-aliasing to prevent gcc from taking advantage of
-# this aspect of the C spec.
-basis/Real/%-gdb.o: basis/Real/%.c gdtoa/arith.h $(HFILES)
-	$(CC) $(DEBUGCFLAGS) $(DEBUGWARNCFLAGS) -Wno-float-equal -c -o $@ $<
-basis/Real/%.o: basis/Real/%.c gdtoa/arith.h  $(HFILES)
-	$(CC) $(OPTCFLAGS) $(OPTWARNCFLAGS) -Wno-float-equal -O1 -fno-strict-aliasing -c -o $@ $<
-
 %-gdb.o: %.c $(HFILES)
 	$(CC) $(DEBUGCFLAGS) $(DEBUGWARNCFLAGS) -c -o $@ $<
 

Modified: mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/class.c
===================================================================
--- mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/class.c	2007-04-13 23:20:47 UTC (rev 5524)
+++ mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/class.c	2007-04-14 18:53:21 UTC (rev 5525)
@@ -14,9 +14,9 @@
 
 #else
 
-/* This code assumes IEEE 754/854 and little endian.
+/* This code assumes IEEE 754/854.
  *
- * In memory, the 32 bits of a float are layed out as follows.
+ * In little-endian memory, the 32 bits of a float are layed out as follows.
  *
  * d[0]  bits 7-0 of mantissa
  * d[1]  bits 15-8 of mantissa
@@ -24,9 +24,18 @@
  *       bits 22-16 of mantissa
  * d[3]  sign bit
  *       bits 7-1 of exponent
+ *
+ * In big-endian memory, the 32 bits of a float are layed out as follows.
+ *
+ * d[3]  bits 7-0 of mantissa
+ * d[2]  bits 15-8 of mantissa
+ * d[1]  bit  0 of exponent
+ *       bits 22-16 of mantissa
+ * d[0]  sign bit
+ *       bits 7-1 of exponent
  */
 
-/* masks for word 0 */
+/* masks for least/most significant word */
 #define EXPONENT_MASK32 0x7F800000
 #define MANTISSA_MASK32 0x007FFFFF
 #define SIGNBIT_MASK32  0x80000000
@@ -36,7 +45,21 @@
   uint32_t word0;
   int res;
 
-  word0 = ((uint32_t *)&f)[0];  /* this generates a gcc warning */
+  /* Using memcpy;
+   * Technically correct.
+   */
+  uint32_t words[1];
+  memcpy(&words, &f, sizeof(Real32_t));
+  word0 = words[0];
+  /* Using union;
+   * Technically undefined, but widely supported.
+   */
+  /*
+  union {float f; uint32_t words[1];} fws;
+  fws.f = f;
+  word0 = fws.words[0];
+  */
+
   if ((word0 & EXPONENT_MASK32) == EXPONENT_MASK32) {
     if (word0 & MANTISSA_MASK32)
       res = FP_NAN;
@@ -68,11 +91,9 @@
 
 #else
 
-#if (defined __i386__)
-
-/* This code assumes IEEE 754/854 and little endian.
+/* This code assumes IEEE 754/854.
  *
- * In memory, the 64 bits of a double are layed out as follows.
+ * In little-endian memory, the 64 bits of a double are layed out as follows.
  *
  * d[0]  bits 7-0 of mantissa
  * d[1]  bits 15-8 of mantissa
@@ -84,9 +105,22 @@
  *       bits 51-48 of mantissa
  * d[7]  sign bit
  *       bits 10-4 of exponent
+ *
+ * In big-endian memory, the 64 bits of a double are layed out as follows.
+ *
+ * d[7]  bits 7-0 of mantissa
+ * d[6]  bits 15-8 of mantissa
+ * d[5]  bits 23-16 of mantissa
+ * d[4]  bits 31-24 of mantissa
+ * d[3]  bits 39-32 of mantissa
+ * d[2]  bits 47-40 of mantissa
+ * d[1]  bits 3-0 of exponent
+ *       bits 51-48 of mantissa
+ * d[0]  sign bit
+ *       bits 10-4 of exponent
  */
 
-/* masks for word 1 */
+/* masks for most-significant word */
 #define EXPONENT_MASK64 0x7FF00000
 #define MANTISSA_MASK64 0x000FFFFF
 #define SIGNBIT_MASK64  0x80000000
@@ -96,8 +130,33 @@
   uint32_t word0, word1;
   int res;
 
-  word0 = ((uint32_t*)&d)[0];
-  word1 = ((uint32_t*)&d)[1];
+  /* Using memcpy;
+   * Technically correct.
+   */
+  uint32_t words[2];
+  memcpy(&words, &d, sizeof(Real64_t));
+  if (isBigEndian()) {
+    word1 = words[0];
+    word0 = words[1];
+  } else {
+    word0 = words[0];
+    word1 = words[1];
+  }
+  /* Using union;
+   * Technically undefined, but widely supported.
+   */
+  /*
+  union {double d; uint32_t words[2];} dws;
+  dws.d = d;
+  if (isBigEndian()) {
+    word1 = dws.words[0];
+    word0 = dws.words[1];
+  } else {
+    word0 = dws.words[0];
+    word1 = dws.words[1];
+  }
+  */
+
   if ((word1 & EXPONENT_MASK64) == EXPONENT_MASK64) {
     if (word0 or (word1 & MANTISSA_MASK64))
       res = FP_NAN;
@@ -112,10 +171,4 @@
   return res;
 }
 
-#else
-
-#error Real64_class not implemented
-
 #endif
-
-#endif

Modified: mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/gdtoa.c
===================================================================
--- mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/gdtoa.c	2007-04-13 23:20:47 UTC (rev 5524)
+++ mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/gdtoa.c	2007-04-14 18:53:21 UTC (rev 5525)
@@ -11,19 +11,11 @@
   int ex;
   static FPI fpi = { 24, 1-127-24+1,  254-127-24+1, 1, 0 };
   int i;
-  ULong *L;
+  ULong L[1];
   char *result;
   ULong sign;
-  int x0, x1;
 
-  if (MLton_Platform_Arch_bigendian) {
-    x0 = 0;
-    x1 = 1;
-  } else {
-    x0 = 1;
-    x1 = 0;
-  }
-  L = (ULong*)&f;
+  memcpy(L, &f, sizeof(Real32_t));
   sign = L[0] & 0x80000000L;
   bits[0] = L[0] & 0x7fffff;
   if (0 != (ex = (L[0] >> 23) & 0xff))
@@ -44,19 +36,19 @@
   int ex;
   static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0 };
   int i;
-  ULong *L;
+  ULong L[2];
   char *result;
   ULong sign;
   int x0, x1;
 
-  if (MLton_Platform_Arch_bigendian) {
+  if (isBigEndian()) {
     x0 = 0;
     x1 = 1;
   } else {
     x0 = 1;
     x1 = 0;
   }
-  L = (ULong*)&d;
+  memcpy(L, &d, sizeof(Real64_t));
   sign = L[x0] & 0x80000000L;
   bits[0] = L[x1];
   bits[1] = L[x0] & 0xfffff;

Modified: mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/signBit.c
===================================================================
--- mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/signBit.c	2007-04-13 23:20:47 UTC (rev 5524)
+++ mlton/branches/on-20050822-x86_64-branch/runtime/basis/Real/signBit.c	2007-04-14 18:53:21 UTC (rev 5525)
@@ -12,32 +12,74 @@
 
 #else
 
-#if (defined __i386__)
-
 enum {
-  R32_byte = 3,
-  R64_byte = 7,
+  LITTLE_R32_byte = 3,
+  LITTLE_R64_byte = 7,
 };
 
-#elif (defined __ppc__ || defined __sparc__)
-
 enum {
-  R32_byte = 0,
-  R64_byte = 0,
+  BIG_R32_byte = 0,
+  BIG_R64_byte = 0,
 };
 
-#else
+C_Int_t Real32_signBit (Real32_t f) {
+  int R32_byte;
+  if (isBigEndian()) {
+    R32_byte = BIG_R32_byte;
+  } else {
+    R32_byte = LITTLE_R32_byte;
+  }
 
-#error Real_signBit not implemented
-
-#endif
-
-C_Int_t Real32_signBit (Real32_t f) {
-  return (((unsigned char *)&f)[R32_byte] & 0x80) >> 7;
+  /* Using memcpy. 
+   * Technically correct.
+   */
+  unsigned char chars[4];
+  memcpy(chars, &f, sizeof(Real32_t));
+  return (chars[R32_byte] & 0x80) >> 7;
+  /* Using cast; 
+   * Technically correct, as (unsigned char*) may alias.   
+   */
+  /*
+  return (((unsigned char*)(&f))[R32_byte] & 0x80) >> 7;
+  */
+  /* Using union; 
+   * Technically undefined, but widely supported. 
+   */
+  /*
+  union {float f; unsigned char c[4];} fc;
+  fc.f = f;
+  return (fc.c[R32_byte] & 0x80) >> 7;
+  */
 }
 
 C_Int_t Real64_signBit (Real64_t d) {
-  return (((unsigned char *)&d)[R64_byte] & 0x80) >> 7;
+  int R64_byte;
+  if (isBigEndian()) {
+    R64_byte = BIG_R64_byte;
+  } else {
+    R64_byte = LITTLE_R64_byte;
+  }
+
+  /* Using memcpy. 
+   * Technically correct.
+   */
+  unsigned char chars[8];
+  memcpy(chars, &d, sizeof(Real64_t));
+  return (chars[R64_byte] & 0x80) >> 7;
+  /* Using cast; 
+   * Technically correct, as (unsigned char*) may alias.   
+   */
+  /*
+  return (((unsigned char*)(&d))[R64_byte] & 0x80) >> 7;
+  */
+  /* Using union; 
+   * Technically undefined, but widely supported. 
+   */
+  /*
+  union {double d; unsigned char c[8];} dc;
+  dc.d = d;
+  return (dc.c[R64_byte] & 0x80) >> 7;
+  */
 }
 
 #endif




More information about the MLton-commit mailing list