This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: A possible bug in parsing floating point numbers.


On Thu, Apr 04, 2002 at 02:39:46PM -0800, tm wrote:
...
> If you look closely, the value 1.0f has been encoded twice in TWO
> different ways.
> 
> The first one is the static initialization of b which is encoded as
> 1065353218. In hexadecimal this value is 0x3f800002 which is incorrect.
> 
> The second value is one of the arguments passed to ___ltsf2. This value
> is 106535217 which is hexadecimal 0x3f800001 which is also incorrect.

I apologize for the delay in returning to this bug.  I was tied down
with other work.  Your further analysis of the problem -- buffer
overflow due to blindly calling etoe53 in PUT_REAL -- was correct.

My fix for this is to recognize that real.c fundamentally expects
REAL_VALUE_TYPE to be either 96 or 160 bits wide, no matter what the
maximum precision of the target's floating point is.  Further, it does
all the necessary rounding itself before calling PUT_REAL, so
attempting to round again is simply incorrect.  The appended patch
causes GET/PUT_REAL to perform no conversion at all, and corrects the
size calculated for REAL_VALUE_TYPE.  I get 

_b:
        .long   1065353216
        .global ___ltsf2
        .section        .rodata
        .align 2
.LC0:
        .long   1065353216

with your test case, and 

.LC0:
        .long   1073741824
        .align 2
.LC1:
        .long   1082130432

with Kazu's; I believe both are correct.  I am now setting up a
H8300 simulator with which to test the patch thoroughly.

zw

	* real.h: Kill single-letter macros in definition of
	REAL_VALUE_TYPE.  New macro REAL_VALUE_TYPE_SIZE, is either 96
	or 160.  Use it to define REAL_WIDTH; use REAL_WIDTH to size
	REAL_VALUE_TYPE.  The upshot is, REAL_VALUE_TYPE is always
	either 96 or 160 bits wide, such that real.c's "UEMUSHORT e[NE]"
	format always fits it exactly.  Provide CONST_DOUBLE_FORMAT.
	Issue #error for unsupported REAL_WIDTH rather than relying on
	later syntax errors.
	* real.c: Nuke EMU_NON_COMPILE (which would have gone by
	silently until the link failed) in favor of #error.
	Disentangle calculation of NE; document that it's always
	either 96 or 160 bits.  Cause compile to fail if
	REAL_VALUE_TYPE doesn't fit UEMUSHORT e[NE] exactly.  Always
	define GET_REAL and PUT_REAL as bare memcpy-s.

	* gengenrtl.c, rtl.c: Delete logic to calculate REAL_WIDTH and
	CONST_DOUBLE_FORMAT; now provided by real.h.

===================================================================
Index: real.h
--- real.h	25 Mar 2002 20:52:12 -0000	1.39
+++ real.h	18 Apr 2002 00:09:27 -0000
@@ -76,19 +76,49 @@ Software Foundation, 59 Temple Place - S
 /* **** Start of software floating point emulator interface macros **** */
 
 /* REAL_VALUE_TYPE is an array of the minimum number of HOST_WIDE_INTs
-   required to hold MAX_LONG_DOUBLE_TYPE_SIZE bits.  */
-#if MAX_LONG_DOUBLE_TYPE_SIZE == 128
-/* For 128 bit reals, we calculate internally with extra precision.  */
-#define N (160 / BITS_PER_UNIT)
+   required to hold either a 96- or 160-bit extended precision floating
+   point type.  This is true even if the maximum precision floating
+   point type on the target is smaller.  */
+#if MAX_LONG_DOUBLE_TYPE_SIZE == 128 && !INTEL_EXTENDED_IEEE_FORMAT
+#define REAL_VALUE_TYPE_SIZE 160
 #else
-#define N (MAX_LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)
+#define REAL_VALUE_TYPE_SIZE 96
 #endif
-#define S sizeof (HOST_WIDE_INT)
+#define REAL_WIDTH \
+  (REAL_VALUE_TYPE_SIZE/HOST_BITS_PER_WIDE_INT \
+   + (REAL_VALUE_TYPE_SIZE%HOST_BITS_PER_WIDE_INT ? 1 : 0)) /* round up */
 typedef struct {
-  HOST_WIDE_INT r[N/S + (N%S ? 1 : 0)]; /* round up */
+  HOST_WIDE_INT r[REAL_WIDTH];
 } REAL_VALUE_TYPE;
-#undef N
-#undef S
+
+/* Calculate the format for CONST_DOUBLE.  We need as many slots as
+   are necessary to overlay a REAL_VALUE_TYPE on them.  This could be
+   as many as five (32-bit HOST_WIDE_INT, 160-bit REAL_VALUE_TYPE).
+
+   A number of places assume that there are always at least two 'w'
+   slots in a CONST_DOUBLE, so we provide them even if one would suffice.  */
+
+#if REAL_WIDTH == 1
+# define CONST_DOUBLE_FORMAT	 "0ww"
+#else
+# if REAL_WIDTH == 2
+#  define CONST_DOUBLE_FORMAT	 "0ww"
+# else
+#  if REAL_WIDTH == 3
+#   define CONST_DOUBLE_FORMAT	 "0www"
+#  else
+#   if REAL_WIDTH == 4
+#    define CONST_DOUBLE_FORMAT	 "0wwww"
+#   else
+#    if REAL_WIDTH == 5
+#     define CONST_DOUBLE_FORMAT "0wwwww"
+#    else
+      #error "REAL_WIDTH > 5 not supported"
+#    endif
+#   endif
+#  endif
+# endif
+#endif
 
 extern unsigned int significand_size	PARAMS ((enum machine_mode));
 
===================================================================
Index: real.c
--- real.c	23 Mar 2002 01:10:33 -0000	1.65
+++ real.c	18 Apr 2002 00:09:27 -0000
@@ -165,8 +165,7 @@ unknown arithmetic type
 #define EMUSHORT_SIZE HOST_BITS_PER_LONG
 #define EMULONG_SIZE (2 * HOST_BITS_PER_LONG)
 #else
-/*  You will have to modify this program to have a smaller unit size.  */
-#define EMU_NON_COMPILE
+  #error "You will have to modify this program to have a smaller unit size."
 #endif
 #endif
 #endif
@@ -199,92 +198,45 @@ typedef unsigned int UHItype __attribute
 #if HOST_BITS_PER_LONGLONG >= EMULONG_SIZE
 #define EMULONG long long int
 #else
-/*  You will have to modify this program to have a smaller unit size.  */
-#define EMU_NON_COMPILE
+  #error "You will have to modify this program to have a smaller unit size."
 #endif
 #endif
 #endif
 #endif
 
-
-/* The host interface doesn't work if no 16-bit size exists.  */
 #if EMUSHORT_SIZE != 16
-#define EMU_NON_COMPILE
+  #error "The host interface doesn't work if no 16-bit size exists."
 #endif
 
-/* OK to continue compilation.  */
-#ifndef EMU_NON_COMPILE
-
-/* Construct macros to translate between REAL_VALUE_TYPE and e type.
-   In GET_REAL and PUT_REAL, r and e are pointers.
-   A REAL_VALUE_TYPE is guaranteed to occupy contiguous locations
-   in memory, with no holes.  */
+/* Calculate the size of the generic "e" type.  This always has
+   identical in-memory size and representation to REAL_VALUE_TYPE.
+   There are only two supported sizes: ten and six 16-bit words (160
+   or 96 bits).  */
 
-#if MAX_LONG_DOUBLE_TYPE_SIZE == 96 || \
-    ((INTEL_EXTENDED_IEEE_FORMAT != 0) && MAX_LONG_DOUBLE_TYPE_SIZE == 128)
-/* Number of 16 bit words in external e type format */
+#if MAX_LONG_DOUBLE_TYPE_SIZE == 128 && !INTEL_EXTENDED_IEEE_FORMAT
+/* TFmode */
+# define NE 10
+# define MAXDECEXP 4932
+# define MINDECEXP -4977
+#else
 # define NE 6
 # define MAXDECEXP 4932
 # define MINDECEXP -4956
-# define GET_REAL(r,e)  memcpy ((e), (r), 2*NE)
-# define PUT_REAL(e,r)						\
-	do {							\
-	  memcpy ((r), (e), 2*NE);				\
-	  if (2*NE < sizeof (*r))				\
-	    memset ((char *) (r) + 2*NE, 0, sizeof (*r) - 2*NE);	\
-	} while (0)
-# else /* no XFmode */
-#  if MAX_LONG_DOUBLE_TYPE_SIZE == 128
-#   define NE 10
-#   define MAXDECEXP 4932
-#   define MINDECEXP -4977
-#   define GET_REAL(r,e) memcpy ((e), (r), 2*NE)
-#   define PUT_REAL(e,r)					\
-	do {							\
-	  memcpy ((r), (e), 2*NE);				\
-	  if (2*NE < sizeof (*r))				\
-	    memset ((char *) (r) + 2*NE, 0, sizeof (*r) - 2*NE);	\
-	} while (0)
-#else
-#define NE 6
-#define MAXDECEXP 4932
-#define MINDECEXP -4956
-/* Emulator uses target format internally
-   but host stores it in host endian-ness.  */
-
-#define GET_REAL(r,e)							\
-do {									\
-     if (HOST_FLOAT_WORDS_BIG_ENDIAN == REAL_WORDS_BIG_ENDIAN)		\
-       e53toe ((const UEMUSHORT *) (r), (e));				\
-     else								\
-       {								\
-	 UEMUSHORT w[4];					\
-         memcpy (&w[3], ((const EMUSHORT *) r), sizeof (EMUSHORT));	\
-         memcpy (&w[2], ((const EMUSHORT *) r) + 1, sizeof (EMUSHORT));	\
-         memcpy (&w[1], ((const EMUSHORT *) r) + 2, sizeof (EMUSHORT));	\
-         memcpy (&w[0], ((const EMUSHORT *) r) + 3, sizeof (EMUSHORT));	\
-	 e53toe (w, (e));						\
-       }								\
-   } while (0)
-
-#define PUT_REAL(e,r)							\
-do {									\
-     if (HOST_FLOAT_WORDS_BIG_ENDIAN == REAL_WORDS_BIG_ENDIAN)		\
-       etoe53 ((e), (UEMUSHORT *) (r));				\
-     else								\
-       {								\
-	 UEMUSHORT w[4];					\
-	 etoe53 ((e), w);						\
-         memcpy (((EMUSHORT *) r), &w[3], sizeof (EMUSHORT));		\
-         memcpy (((EMUSHORT *) r) + 1, &w[2], sizeof (EMUSHORT));	\
-         memcpy (((EMUSHORT *) r) + 2, &w[1], sizeof (EMUSHORT));	\
-         memcpy (((EMUSHORT *) r) + 3, &w[0], sizeof (EMUSHORT));	\
-       }								\
-   } while (0)
+#endif
+
+/* Fail compilation if 2*NE is not the appropriate size.  */
 
-#endif /* not TFmode */
-#endif /* not XFmode */
+struct compile_test_dummy {
+  char twice_NE_must_equal_sizeof_REAL_VALUE_TYPE
+  [(sizeof (REAL_VALUE_TYPE) == 2*NE) ? 1 : -1];
+};
 
+/* Construct macros to translate between REAL_VALUE_TYPE and e type.
+   In GET_REAL and PUT_REAL, r and e are pointers.
+   A REAL_VALUE_TYPE is guaranteed to occupy contiguous locations
+   in memory, with no holes.  */
+#define GET_REAL(r, e)  memcpy ((e), (r), 2*NE)
+#define PUT_REAL(e, r)  memcpy ((r), (e), 2*NE)
 
 /* Number of 16 bit words in internal format */
 #define NI (NE+3)
@@ -6918,7 +6870,6 @@ esqrt (x, y)
   emovo (sq, y);
 }
 #endif
-#endif /* EMU_NON_COMPILE not defined */
 
 /* Return the binary precision of the significand for a given
    floating point mode.  The mode can hold an integer value
===================================================================
Index: gengenrtl.c
--- gengenrtl.c	3 Mar 2002 21:09:46 -0000	1.51
+++ gengenrtl.c	18 Apr 2002 00:09:26 -0000
@@ -28,69 +28,6 @@ Software Foundation, 59 Temple Place - S
 
 #include "real.h"
 
-/* Calculate the format for CONST_DOUBLE.  This depends on the relative
-   widths of HOST_WIDE_INT and REAL_VALUE_TYPE.
-
-   We need to go out to e0wwwww, since real.c assumes 16 bits per element
-   in REAL_VALUE_TYPE.
-
-   This is duplicated in rtl.c.
-
-   A number of places assume that there are always at least two 'w'
-   slots in a CONST_DOUBLE, so we provide them even if one would suffice.  */
-
-#if MAX_LONG_DOUBLE_TYPE_SIZE == 96
-# define REAL_WIDTH	\
-     (11*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
-#else
-# if MAX_LONG_DOUBLE_TYPE_SIZE == 128
-#  define REAL_WIDTH	\
-     (19*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
-# else
-#  if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-#   define REAL_WIDTH	\
-      (7*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
-#  endif
-# endif
-#endif
-
-#ifndef REAL_WIDTH
-# if HOST_BITS_PER_WIDE_INT*2 >= MAX_LONG_DOUBLE_TYPE_SIZE
-#  define REAL_WIDTH	2
-# else
-#  if HOST_BITS_PER_WIDE_INT*3 >= MAX_LONG_DOUBLE_TYPE_SIZE
-#   define REAL_WIDTH	3
-#  else
-#   if HOST_BITS_PER_WIDE_INT*4 >= MAX_LONG_DOUBLE_TYPE_SIZE
-#    define REAL_WIDTH	4
-#   endif
-#  endif
-# endif
-#endif /* REAL_WIDTH */
-
-#if REAL_WIDTH == 1
-# define CONST_DOUBLE_FORMAT	"0ww"
-#else
-# if REAL_WIDTH == 2
-#  define CONST_DOUBLE_FORMAT	"0ww"
-# else
-#  if REAL_WIDTH == 3
-#   define CONST_DOUBLE_FORMAT	"0www"
-#  else
-#   if REAL_WIDTH == 4
-#    define CONST_DOUBLE_FORMAT	"0wwww"
-#   else
-#    if REAL_WIDTH == 5
-#     define CONST_DOUBLE_FORMAT	"0wwwww"
-#    else
-#     define CONST_DOUBLE_FORMAT /* nothing - will cause syntax error */
-#    endif
-#   endif
-#  endif
-# endif
-#endif
-
-
 struct rtx_definition 
 {
   const char *const enumname, *const name, *const format;
===================================================================
Index: rtl.c
--- rtl.c	8 Mar 2002 12:29:13 -0000	1.110
+++ rtl.c	18 Apr 2002 00:09:27 -0000
@@ -27,68 +27,6 @@ Software Foundation, 59 Temple Place - S
 #include "errors.h"
 
 
-/* Calculate the format for CONST_DOUBLE.  This depends on the relative
-   widths of HOST_WIDE_INT and REAL_VALUE_TYPE.
-
-   We need to go out to 0wwwww, since real.c assumes 16 bits per element
-   in REAL_VALUE_TYPE.
-
-   This is duplicated in gengenrtl.c.
-
-   A number of places assume that there are always at least two 'w'
-   slots in a CONST_DOUBLE, so we provide them even if one would suffice.  */
-
-#if MAX_LONG_DOUBLE_TYPE_SIZE == 96
-# define REAL_WIDTH	\
-     (11*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
-#else
-# if MAX_LONG_DOUBLE_TYPE_SIZE == 128
-#  define REAL_WIDTH	\
-      (19*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
-# else
-#  if HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-#   define REAL_WIDTH	\
-       (7*8 + HOST_BITS_PER_WIDE_INT)/HOST_BITS_PER_WIDE_INT
-#  endif
-# endif
-#endif
-
-#ifndef REAL_WIDTH
-# if HOST_BITS_PER_WIDE_INT*2 >= MAX_LONG_DOUBLE_TYPE_SIZE
-#  define REAL_WIDTH	2
-# else
-#  if HOST_BITS_PER_WIDE_INT*3 >= MAX_LONG_DOUBLE_TYPE_SIZE
-#   define REAL_WIDTH	3
-#  else
-#   if HOST_BITS_PER_WIDE_INT*4 >= MAX_LONG_DOUBLE_TYPE_SIZE
-#    define REAL_WIDTH	4
-#   endif
-#  endif
-# endif
-#endif /* REAL_WIDTH */
-
-#if REAL_WIDTH == 1
-# define CONST_DOUBLE_FORMAT	"0ww"
-#else
-# if REAL_WIDTH == 2
-#  define CONST_DOUBLE_FORMAT	"0ww"
-# else
-#  if REAL_WIDTH == 3
-#   define CONST_DOUBLE_FORMAT	"0www"
-#  else
-#   if REAL_WIDTH == 4
-#    define CONST_DOUBLE_FORMAT	"0wwww"
-#   else
-#    if REAL_WIDTH == 5
-#     define CONST_DOUBLE_FORMAT	"0wwwww"
-#    else
-#     define CONST_DOUBLE_FORMAT	/* nothing - will cause syntax error */
-#    endif
-#   endif
-#  endif
-# endif
-#endif
-
 /* Indexed by rtx code, gives number of operands for an rtx with that code.
    Does NOT include rtx header data (code and links).  */
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]