diff --git a/configure.ac b/configure.ac index b6918671e4..74200dd75b 100644 --- a/configure.ac +++ b/configure.ac @@ -1515,6 +1515,12 @@ AC_DEFUN CPPFLAGS="$C_SWITCH_SYSTEM $C_SWITCH_MACHINE $CPPFLAGS" fi +AC_CHECK_SIZEOF([int]) +AC_CHECK_SIZEOF([long int]) +AC_CHECK_SIZEOF([long long int]) +AC_CHECK_SIZEOF([float]) +AC_CHECK_SIZEOF([double]) + # Suppress obsolescent Autoconf test for size_t; Emacs assumes C99 or better. AC_DEFUN([AC_TYPE_SIZE_T]) # Likewise for obsolescent test for uid_t, gid_t; Emacs assumes them. diff --git a/src/alloc.c b/src/alloc.c index ad716f543c..763df583ab 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -2643,12 +2643,14 @@ static int float_block_index = FLOAT_BLOCK_SIZE; static struct Lisp_Float *float_free_list; +#if FLOAT_REPR == FLOAT_TAGGED + /* Return a new float object with value FLOAT_VALUE. */ Lisp_Object -make_float (double float_value) +make_tagged_float (double float_value) { - register Lisp_Object val; + Lisp_Object val; MALLOC_BLOCK_INPUT; @@ -2685,6 +2687,7 @@ make_float (double float_value) return val; } +#endif /*********************************************************************** @@ -5505,6 +5508,7 @@ static Lisp_Object purecopy (Lisp_Object obj) { if (INTEGERP (obj) + || (FLOAT_REPR != FLOAT_TAGGED && FLOATP (obj)) || (! SYMBOLP (obj) && PURE_P (XPNTR (obj))) || SUBRP (obj)) return obj; /* Already pure. */ @@ -6600,8 +6604,11 @@ mark_object (Lisp_Object arg) } case Lisp_Float: - CHECK_ALLOCATED_AND_LIVE (live_float_p); - FLOAT_MARK (XFLOAT (obj)); + if (FLOAT_REPR == FLOAT_TAGGED) + { + CHECK_ALLOCATED_AND_LIVE (live_float_p); + FLOAT_MARK (XFLOAT (obj)); + } break; case_Lisp_Int: @@ -6673,7 +6680,7 @@ survives_gc_p (Lisp_Object obj) break; case Lisp_Float: - survives_p = FLOAT_MARKED_P (XFLOAT (obj)); + survives_p = FLOAT_REPR != FLOAT_TAGGED || FLOAT_MARKED_P (XFLOAT (obj)); break; default: diff --git a/src/lisp.h b/src/lisp.h index bdece817bd..b4ee5656c7 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -81,18 +81,21 @@ DEFINE_GDB_SYMBOL_END (GCTYPEBITS) typedef int EMACS_INT; typedef unsigned int EMACS_UINT; enum { EMACS_INT_WIDTH = INT_WIDTH, EMACS_UINT_WIDTH = UINT_WIDTH }; +# define SIZEOF_EMACS_INT SIZEOF_INT # define EMACS_INT_MAX INT_MAX # define pI "" # elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT typedef long int EMACS_INT; typedef unsigned long EMACS_UINT; enum { EMACS_INT_WIDTH = LONG_WIDTH, EMACS_UINT_WIDTH = ULONG_WIDTH }; +# define SIZEOF_EMACS_INT SIZEOF_LONG_INT # define EMACS_INT_MAX LONG_MAX # define pI "l" # elif INTPTR_MAX <= LLONG_MAX typedef long long int EMACS_INT; typedef unsigned long long int EMACS_UINT; enum { EMACS_INT_WIDTH = LLONG_WIDTH, EMACS_UINT_WIDTH = ULLONG_WIDTH }; +# define SIZEOF_EMACS_INT SIZEOF_LONG_LONG_INT # define EMACS_INT_MAX LLONG_MAX /* MinGW supports %lld only if __USE_MINGW_ANSI_STDIO is non-zero, which is arranged by config.h, and (for mingw.org) if GCC is 6.0 or @@ -618,6 +621,9 @@ enum CHECK_LISP_OBJECT_TYPE { CHECK_LISP_OBJECT_TYPE = false }; INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t, Lisp_Object); +/* Defined in alloc.c. */ +extern Lisp_Object make_tagged_float (double); + /* Defined in chartab.c. */ extern Lisp_Object char_table_ref (Lisp_Object, int); extern void char_table_set (Lisp_Object, int, Lisp_Object); @@ -2640,6 +2646,34 @@ XBUFFER_OBJFWD (union Lisp_Fwd *a) } /* Lisp floating point type. */ + +/* Most hosts nowadays use IEEE floating point, so they use IEC 60559 + representations, have infinities and NaNs, and do not trap on + exceptions. Define IEEE_FLOATING_POINT to 1 if this host is one of the + typical ones. The C11 macro __STDC_IEC_559__ is close to what is + wanted here, but is not quite right because Emacs does not require + all the features of C11 Annex F (and does not require C11 at all, + for that matter). */ + +#define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \ + && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128) + +/* Whether Lisp floats are represented directly in Lisp_Object values, + as opposed to tagged pointers to storage. */ +#define FLOAT_TAGGED 0 +#define FLOAT_FLOAT 1 +#define FLOAT_DOUBLE 2 +#define FLOAT_REPR (! (USE_LSB_TAG && IEEE_FLOATING_POINT) ? FLOAT_TAGGED \ + : SIZEOF_EMACS_INT == SIZEOF_FLOAT ? FLOAT_FLOAT \ + : SIZEOF_EMACS_INT == SIZEOF_DOUBLE ? FLOAT_DOUBLE \ + : FLOAT_TAGGED) +#if FLOAT_REPR == FLOAT_FLOAT +typedef float emacs_float; +#elif FLOAT_REPR == FLOAT_DOUBLE +typedef double emacs_float; +#endif + +/* If Lisp floats are tagged pointers, they point to this. */ struct Lisp_Float { union @@ -2655,9 +2689,21 @@ INLINE bool return lisp_h_FLOATP (x); } +INLINE Lisp_Object +make_float (double d) +{ +#if FLOAT_REPR == FLOAT_TAGGED + return make_tagged_float (d); +#else + return XIL (((union { emacs_float f; EMACS_INT i; }) {d} . i & VALMASK) + + Lisp_Float); +#endif +} + INLINE struct Lisp_Float * XFLOAT (Lisp_Object a) { + eassume (FLOAT_REPR == FLOAT_TAGGED); eassert (FLOATP (a)); return XUNTAG (a, Lisp_Float, struct Lisp_Float); } @@ -2665,19 +2711,18 @@ XFLOAT (Lisp_Object a) INLINE double XFLOAT_DATA (Lisp_Object f) { - return XFLOAT (f)->u.data; -} - -/* Most hosts nowadays use IEEE floating point, so they use IEC 60559 - representations, have infinities and NaNs, and do not trap on - exceptions. Define IEEE_FLOATING_POINT to 1 if this host is one of the - typical ones. The C11 macro __STDC_IEC_559__ is close to what is - wanted here, but is not quite right because Emacs does not require - all the features of C11 Annex F (and does not require C11 at all, - for that matter). */ + union { EMACS_INT i; float f; double d; } u = { .i = XLI (f) - Lisp_Float }; -#define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \ - && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128) + switch (FLOAT_REPR) + { + case FLOAT_FLOAT: + return u.f; + case FLOAT_DOUBLE: + return u.d; + default: + return XFLOAT (f)->u.data; + } +} /* A character, declared with the following typedef, is a member of some character set associated with the current buffer. */ @@ -3696,7 +3741,6 @@ extern struct Lisp_Vector *allocate_pseudovector (int, int, int, VECSIZE (type), tag)) extern bool gc_in_progress; -extern Lisp_Object make_float (double); extern void display_malloc_warning (void); extern ptrdiff_t inhibit_garbage_collection (void); extern Lisp_Object build_overlay (Lisp_Object, Lisp_Object, Lisp_Object); diff --git a/src/print.c b/src/print.c index 34c7fa12b6..c10bbc5ac2 100644 --- a/src/print.c +++ b/src/print.c @@ -39,6 +39,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #if IEEE_FLOATING_POINT # include @@ -1029,7 +1030,26 @@ float_to_string (char *buf, double data) { /* Generate the fewest number of digits that represent the floating point value without losing information. */ - len = dtoastr (buf, FLOAT_TO_STRING_BUFSIZE - 2, 0, 0, data); + if (FLOAT_REPR == FLOAT_TAGGED) + len = dtoastr (buf, FLOAT_TO_STRING_BUFSIZE - 2, 0, 0, data); + else + for (int prec = ((fabs (data) + < (FLOAT_REPR == FLOAT_FLOAT + ? (double) FLT_MIN + : DBL_MIN)) + ? 1 + : ((FLOAT_REPR == FLOAT_FLOAT ? FLT_DIG : DBL_DIG) + - 1)); + ; prec++) + { + len = snprintf (buf, FLOAT_TO_STRING_BUFSIZE - 2, + "%.*g", prec, data); + if (isnan (data)) + break; + if (XFLOAT_DATA (make_float (strtod (buf, NULL))) == data) + break; + } + /* The decimal point must be printed, or the byte compiler can get confused (Bug#8033). */ width = 1;