From d216d7d248199aa6c99cd642116717c5b301ae6d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 1 Aug 2018 18:53:31 -0700 Subject: [PATCH] Substitute a on hosts lacking it * .gitignore: Add lib/ieee754.h. * admin/merge-gnulib (GNULIB_MODULES): Add ieee754-h. * configure.ac: Remove ieee754.h check, as Gnulib now does that. * etc/NEWS: Mention this. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * lib/ieee754.in.h, m4/ieee754-h.m4: New files, from Gnulib. * src/lisp.h (IEEE_FLOATING_POINT): Now a macro so that it can be used in #if. * src/lread.c, src/print.c: Include if IEEE_FLOATING_POINT, not if HAVE_IEEE754_H. * src/lread.c (string_to_number): * src/print.c (float_to_string): Process NaNs only on IEEE hosts, and assume in that case. --- .gitignore | 1 + admin/merge-gnulib | 2 +- configure.ac | 1 - etc/NEWS | 6 +- lib/gnulib.mk.in | 29 ++++++ lib/ieee754.in.h | 222 +++++++++++++++++++++++++++++++++++++++++++++ m4/gnulib-comp.m4 | 4 + m4/ieee754-h.m4 | 21 +++++ src/lisp.h | 11 +-- src/lread.c | 9 +- src/print.c | 25 +---- 11 files changed, 291 insertions(+), 40 deletions(-) create mode 100644 lib/ieee754.in.h create mode 100644 m4/ieee754-h.m4 diff --git a/.gitignore b/.gitignore index d3712b0d6cf..26fe4bb34e8 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,7 @@ lib/execinfo.h lib/fcntl.h lib/getopt.h lib/getopt-cdefs.h +lib/ieee754.h lib/inttypes.h lib/libgnu.a lib/limits.h diff --git a/admin/merge-gnulib b/admin/merge-gnulib index 39dfaee8f4d..1397ecfb9f7 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -35,7 +35,7 @@ GNULIB_MODULES=' fcntl fcntl-h fdatasync fdopendir filemode filevercmp flexmember fpieee fstatat fsusage fsync getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog - ignore-value intprops largefile lstat + ieee754-h ignore-value intprops largefile lstat manywarnings memrchr minmax mkostemp mktime nstrftime pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat sig2str socklen stat-time std-gnu11 stdalign stddef stdio diff --git a/configure.ac b/configure.ac index dbdcce7c8d8..b6918671e40 100644 --- a/configure.ac +++ b/configure.ac @@ -1668,7 +1668,6 @@ fi dnl checks for header files AC_CHECK_HEADERS_ONCE( - ieee754.h linux/fs.h malloc.h sys/systeminfo.h diff --git a/etc/NEWS b/etc/NEWS index 9e7a765dc61..6c79a46f243 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -880,9 +880,9 @@ Formerly, some of these functions ignored signs and significands of NaNs. Now, all these functions treat NaN signs and significands as significant. For example, (eql 0.0e+NaN -0.0e+NaN) now returns nil because the two NaNs have different signs; formerly it returned t. -Also, on platforms that have Emacs now reads and prints -NaN significands; e.g., if X is a NaN, (format "%s" X) now returns -"0.0e+NaN", "1.0e+NaN", etc., depending on X's significand. +Also, Emacs now reads and prints NaN significands; e.g., if X is a +NaN, (format "%s" X) now returns "0.0e+NaN", "1.0e+NaN", etc., +depending on X's significand. +++ ** The function 'make-string' accepts an additional optional argument. diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index e623921091f..7d28dcc62b8 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -95,6 +95,7 @@ # gettime \ # gettimeofday \ # gitlog-to-changelog \ +# ieee754-h \ # ignore-value \ # intprops \ # largefile \ @@ -220,6 +221,7 @@ GL_GENERATE_ALLOCA_H = @GL_GENERATE_ALLOCA_H@ GL_GENERATE_BYTESWAP_H = @GL_GENERATE_BYTESWAP_H@ GL_GENERATE_ERRNO_H = @GL_GENERATE_ERRNO_H@ GL_GENERATE_EXECINFO_H = @GL_GENERATE_EXECINFO_H@ +GL_GENERATE_IEEE754_H = @GL_GENERATE_IEEE754_H@ GL_GENERATE_LIMITS_H = @GL_GENERATE_LIMITS_H@ GL_GENERATE_STDALIGN_H = @GL_GENERATE_STDALIGN_H@ GL_GENERATE_STDDEF_H = @GL_GENERATE_STDDEF_H@ @@ -646,6 +648,7 @@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@ HAVE_XSERVER = @HAVE_XSERVER@ HAVE__EXIT = @HAVE__EXIT@ HYBRID_MALLOC = @HYBRID_MALLOC@ +IEEE754_H = @IEEE754_H@ IMAGEMAGICK_CFLAGS = @IMAGEMAGICK_CFLAGS@ IMAGEMAGICK_LIBS = @IMAGEMAGICK_LIBS@ INCLUDE_NEXT = @INCLUDE_NEXT@ @@ -1787,6 +1790,32 @@ EXTRA_libgnu_a_SOURCES += group-member.c endif ## end gnulib module group-member +## begin gnulib module ieee754-h +ifeq (,$(OMIT_GNULIB_MODULE_ieee754-h)) + +BUILT_SOURCES += $(IEEE754_H) + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +ifneq (,$(GL_GENERATE_IEEE754_H)) +ieee754.h: ieee754.in.h $(top_builddir)/config.status + $(AM_V_GEN)rm -f $@-t && \ + { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \ + sed -e 's/ifndef _GL_GNULIB_HEADER/if 0/g' \ + $(srcdir)/ieee754.in.h; \ + } > $@-t && \ + mv -f $@-t $@ +else +ieee754.h: $(top_builddir)/config.status + rm -f $@ +endif +MOSTLYCLEANFILES += ieee754.h ieee754.h-t + +EXTRA_DIST += ieee754.in.h + +endif +## end gnulib module ieee754-h + ## begin gnulib module ignore-value ifeq (,$(OMIT_GNULIB_MODULE_ignore-value)) diff --git a/lib/ieee754.in.h b/lib/ieee754.in.h new file mode 100644 index 00000000000..316ac039afe --- /dev/null +++ b/lib/ieee754.in.h @@ -0,0 +1,222 @@ +/* Copyright (C) 1992-2018 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _IEEE754_H + +#define _IEEE754_H 1 + +#ifndef _GL_GNULIB_HEADER +/* Ordinary glibc usage. */ +# include +# include +#else +/* Gnulib usage. */ +# ifndef __BEGIN_DECLS +# ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +# else +# define __BEGIN_DECLS +# define __END_DECLS +# endif +# endif +# ifndef __FLOAT_WORD_ORDER +# define __LITTLE_ENDIAN 1234 +# define __BIG_ENDIAN 4321 +# ifdef WORDS_BIGENDIAN +# define __BYTE_ORDER __BIG_ENDIAN +# else +# define __BYTE_ORDER __LITTLE_ENDIAN +# endif +# define __FLOAT_WORD_ORDER __BYTE_ORDER +# endif +#endif + +__BEGIN_DECLS + +union ieee754_float + { + float f; + + /* This is the IEEE 754 single-precision format. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:8; + unsigned int mantissa:23; +#endif /* Big endian. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int mantissa:23; + unsigned int exponent:8; + unsigned int negative:1; +#endif /* Little endian. */ + } ieee; + + /* This format makes it easier to see if a NaN is a signalling NaN. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:8; + unsigned int quiet_nan:1; + unsigned int mantissa:22; +#endif /* Big endian. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int mantissa:22; + unsigned int quiet_nan:1; + unsigned int exponent:8; + unsigned int negative:1; +#endif /* Little endian. */ + } ieee_nan; + }; + +#define IEEE754_FLOAT_BIAS 0x7f /* Added to exponent. */ + + +union ieee754_double + { + double d; + + /* This is the IEEE 754 double-precision format. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:11; + /* Together these comprise the mantissa. */ + unsigned int mantissa0:20; + unsigned int mantissa1:32; +#endif /* Big endian. */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +# if __FLOAT_WORD_ORDER == __BIG_ENDIAN + unsigned int mantissa0:20; + unsigned int exponent:11; + unsigned int negative:1; + unsigned int mantissa1:32; +# else + /* Together these comprise the mantissa. */ + unsigned int mantissa1:32; + unsigned int mantissa0:20; + unsigned int exponent:11; + unsigned int negative:1; +# endif +#endif /* Little endian. */ + } ieee; + + /* This format makes it easier to see if a NaN is a signalling NaN. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:11; + unsigned int quiet_nan:1; + /* Together these comprise the mantissa. */ + unsigned int mantissa0:19; + unsigned int mantissa1:32; +#else +# if __FLOAT_WORD_ORDER == __BIG_ENDIAN + unsigned int mantissa0:19; + unsigned int quiet_nan:1; + unsigned int exponent:11; + unsigned int negative:1; + unsigned int mantissa1:32; +# else + /* Together these comprise the mantissa. */ + unsigned int mantissa1:32; + unsigned int mantissa0:19; + unsigned int quiet_nan:1; + unsigned int exponent:11; + unsigned int negative:1; +# endif +#endif + } ieee_nan; + }; + +#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */ + + +union ieee854_long_double + { + long double d; + + /* This is the IEEE 854 double-extended-precision format. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:15; + unsigned int empty:16; + unsigned int mantissa0:32; + unsigned int mantissa1:32; +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN +# if __FLOAT_WORD_ORDER == __BIG_ENDIAN + unsigned int exponent:15; + unsigned int negative:1; + unsigned int empty:16; + unsigned int mantissa0:32; + unsigned int mantissa1:32; +# else + unsigned int mantissa1:32; + unsigned int mantissa0:32; + unsigned int exponent:15; + unsigned int negative:1; + unsigned int empty:16; +# endif +#endif + } ieee; + + /* This is for NaNs in the IEEE 854 double-extended-precision format. */ + struct + { +#if __BYTE_ORDER == __BIG_ENDIAN + unsigned int negative:1; + unsigned int exponent:15; + unsigned int empty:16; + unsigned int one:1; + unsigned int quiet_nan:1; + unsigned int mantissa0:30; + unsigned int mantissa1:32; +#endif +#if __BYTE_ORDER == __LITTLE_ENDIAN +# if __FLOAT_WORD_ORDER == __BIG_ENDIAN + unsigned int exponent:15; + unsigned int negative:1; + unsigned int empty:16; + unsigned int mantissa0:30; + unsigned int quiet_nan:1; + unsigned int one:1; + unsigned int mantissa1:32; +# else + unsigned int mantissa1:32; + unsigned int mantissa0:30; + unsigned int quiet_nan:1; + unsigned int one:1; + unsigned int exponent:15; + unsigned int negative:1; + unsigned int empty:16; +# endif +#endif + } ieee_nan; + }; + +#define IEEE854_LONG_DOUBLE_BIAS 0x3fff + +__END_DECLS + +#endif /* ieee754.h */ diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index a6e3be3815d..494c77c7c4e 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -101,6 +101,7 @@ AC_DEFUN([gl_EARLY], # Code from module gettimeofday: # Code from module gitlog-to-changelog: # Code from module group-member: + # Code from module ieee754-h: # Code from module ignore-value: # Code from module include_next: # Code from module intprops: @@ -295,6 +296,7 @@ AC_DEFUN([gl_INIT], gl_PREREQ_GETTIMEOFDAY fi gl_SYS_TIME_MODULE_INDICATOR([gettimeofday]) + gl_IEEE754_H gl_INTTYPES_INCOMPLETE AC_REQUIRE([gl_LARGEFILE]) gl_LIMITS_H @@ -895,6 +897,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/gettimeofday.c lib/gl_openssl.h lib/group-member.c + lib/ieee754.in.h lib/ignore-value.h lib/intprops.h lib/inttypes.in.h @@ -1017,6 +1020,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/gl-openssl.m4 m4/gnulib-common.m4 m4/group-member.m4 + m4/ieee754-h.m4 m4/include_next.m4 m4/inttypes.m4 m4/largefile.m4 diff --git a/m4/ieee754-h.m4 b/m4/ieee754-h.m4 new file mode 100644 index 00000000000..bf7c332e48e --- /dev/null +++ b/m4/ieee754-h.m4 @@ -0,0 +1,21 @@ +# Configure ieee754-h module + +dnl Copyright 2018 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_IEEE754_H], +[ + AC_REQUIRE([AC_C_BIGENDIAN]) + AC_CHECK_HEADERS_ONCE([ieee754.h]) + if test $ac_cv_header_ieee754_h = yes; then + IEEE754_H= + else + IEEE754_H=ieee754.h + AC_DEFINE([_GL_REPLACE_IEEE754_H], 1, + [Define to 1 if is missing.]) + fi + AC_SUBST([IEEE754_H]) + AM_CONDITIONAL([GL_GENERATE_IEEE754_H], [test -n "$IEEE754_H"]) +]) diff --git a/src/lisp.h b/src/lisp.h index 96de60e4670..bdece817bd6 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2670,17 +2670,14 @@ XFLOAT_DATA (Lisp_Object f) /* 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 if this host is one of the + 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). */ -enum - { - IEEE_FLOATING_POINT - = (FLT_RADIX == 2 && FLT_MANT_DIG == 24 - && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128) - }; + +#define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \ + && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128) /* A character, declared with the following typedef, is a member of some character set associated with the current buffer. */ diff --git a/src/lread.c b/src/lread.c index 290b0f6bbe9..9a025d8664d 100644 --- a/src/lread.c +++ b/src/lread.c @@ -72,7 +72,7 @@ along with GNU Emacs. If not, see . */ #define file_tell ftell #endif -#if HAVE_IEEE754_H +#if IEEE_FLOATING_POINT # include #endif @@ -3756,21 +3756,18 @@ string_to_number (char const *string, int base, int flags) cp += 3; value = INFINITY; } +#if IEEE_FLOATING_POINT else if (cp[-1] == '+' && cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N') { state |= E_EXP; cp += 3; -#if HAVE_IEEE754_H union ieee754_double u = { .ieee_nan = { .exponent = -1, .quiet_nan = 1, .mantissa0 = n >> 31 >> 1, .mantissa1 = n }}; value = u.d; -#else - /* NAN is a "positive" NaN on all known Emacs hosts. */ - value = NAN; -#endif } +#endif else cp = ecp; } diff --git a/src/print.c b/src/print.c index add21609cc5..34c7fa12b6e 100644 --- a/src/print.c +++ b/src/print.c @@ -40,7 +40,7 @@ along with GNU Emacs. If not, see . */ #include #include -#if HAVE_IEEE754_H +#if IEEE_FLOATING_POINT # include #endif @@ -1013,34 +1013,15 @@ float_to_string (char *buf, double data) strcpy (buf, minus_infinity_string + positive); return sizeof minus_infinity_string - 1 - positive; } +#if IEEE_FLOATING_POINT if (isnan (data)) { -#if HAVE_IEEE754_H union ieee754_double u = { .d = data }; uprintmax_t hi = u.ieee_nan.mantissa0; return sprintf (buf, &"-%"pMu".0e+NaN"[!u.ieee_nan.negative], (hi << 31 << 1) + u.ieee_nan.mantissa1); -#else - /* Prepend "-" if the NaN's sign bit is negative. - The sign bit of a double is the bit that is 1 in -0.0. */ - static char const NaN_string[] = "0.0e+NaN"; - int i; - union { double d; char c[sizeof (double)]; } u_data, u_minus_zero; - bool negative = 0; - u_data.d = data; - u_minus_zero.d = - 0.0; - for (i = 0; i < sizeof (double); i++) - if (u_data.c[i] & u_minus_zero.c[i]) - { - *buf = '-'; - negative = 1; - break; - } - - strcpy (buf + negative, NaN_string); - return negative + sizeof NaN_string - 1; -#endif } +#endif if (NILP (Vfloat_output_format) || !STRINGP (Vfloat_output_format)) -- 2.39.2