In perl.git, the branch blead has been updated <http://perl5.git.perl.org/perl.git/commitdiff/07bb61ac4e127de8c4d5c8a40adf7cd36baa6253?hp=63545cd8b35d0a75c86800927564a9879ba1e0bf>
- Log ----------------------------------------------------------------- commit 07bb61ac4e127de8c4d5c8a40adf7cd36baa6253 Author: Jarkko Hietaniemi <[email protected]> Date: Tue Jun 2 18:09:54 2015 -0400 infnan: Implement NaN payload APIs. Based on the latest ISO/IEC WG draft: http://www.open-std.org/JTC1/sc22/wg14/www/docs/n1778.pdf (section 14.10, pp 42,45-47). There isn't yet an official C1X effort (these weren't part of C11) so there's no C1X to refer to. M ext/POSIX/POSIX.xs M ext/POSIX/lib/POSIX.pm M ext/POSIX/lib/POSIX.pod M ext/POSIX/t/export.t M ext/POSIX/t/math.t commit 453b60f134ff4079e06d0a4adde0c3f90b71fb2f Author: Jarkko Hietaniemi <[email protected]> Date: Thu Jun 4 08:09:49 2015 -0400 infnan: Notes on the nan payload. M perl.h commit d3137b5f5f06e1a641f5faddf1916829e768876b Author: Jarkko Hietaniemi <[email protected]> Date: Sun Mar 1 16:19:13 2015 -0500 infnan: define NV_NAN_PAYLOAD_MASK and NV_NAN_PAYLOAD_PERM MASK: how to mask the nan payload bytes PERM: how to order the nan payload bytes (0x0 = LSB) M perl.h commit 5a14060af165c24c63cfc5d5f4d2aeb52cc41a03 Author: Jarkko Hietaniemi <[email protected]> Date: Sun Mar 1 20:16:02 2015 -0500 infnan: move the mantbits definitions from perl.h to Configure (this way they will be available via %Config) M Configure M Cross/config.sh-arm-linux M NetWare/config.wc M Porting/Glossary M Porting/config.sh M config_h.SH M configure.com M perl.h M plan9/config_sh.sample M symbian/config.sh M uconfig.sh M uconfig64.sh M win32/config.ce M win32/config.gc M win32/config.vc commit f37aa82892bb09ff8e8c3d28b173de5d2f60d2a4 Author: Jarkko Hietaniemi <[email protected]> Date: Sat Feb 28 13:04:38 2015 -0500 infnan: macros for testing and setting nan quiet/signaling M perl.h commit 5c255b3b67c0e68b1f712c1111b140beb8261a9e Author: Jarkko Hietaniemi <[email protected]> Date: Fri Feb 27 17:17:48 2015 -0500 infnan: introduce NV_NAN_PAYLOAD_BITS M perl.h commit 68652010dea6d81e0211abf18bea20c0e046a006 Author: Jarkko Hietaniemi <[email protected]> Date: Fri Feb 27 16:57:52 2015 -0500 infnan: introduce NV_MANT_BITS (the real bits, not including possible implicit bit) M perl.h commit 9e76e8dd3a4eeeececa2572dad4eb11d8526e286 Author: Jarkko Hietaniemi <[email protected]> Date: Thu Feb 26 20:20:41 2015 -0500 infnan: new logic for NV_INF and NV_NAN The global const PL_inf and PL_nan have dual nature: the .nv has the NV, the .u8 has the bytes. M globvar.sym M perl.h commit ed3917fd69b234bb5614cb9aed93d62238e3dcb8 Author: Jarkko Hietaniemi <[email protected]> Date: Wed Jun 10 22:05:48 2015 -0400 infnan: Configure scan for fp mantissa bytes M Configure M Cross/config.sh-arm-linux M NetWare/config.wc M NetWare/config_H.wc M Porting/Glossary M Porting/config.sh M config_h.SH M configure.com M plan9/config_sh.sample M symbian/config.sh M uconfig.sh M uconfig64.sh M win32/config.ce M win32/config.gc M win32/config.vc M win32/config_H.ce M win32/config_H.gc M win32/config_H.vc commit 44521f3a1782026b7d25cc55af459c3e28cc9bdd Author: Jarkko Hietaniemi <[email protected]> Date: Sat Feb 28 10:23:06 2015 -0500 infnan: Configure scan for infnan bytes M Configure M Cross/config.sh-arm-linux M NetWare/config.wc M NetWare/config_H.wc M Porting/Glossary M Porting/config.sh M config_h.SH M configure.com M plan9/config_sh.sample M symbian/config.sh M uconfig.h M uconfig.sh M uconfig64.sh M win32/config.ce M win32/config.gc M win32/config.vc M win32/config_H.ce M win32/config_H.gc M win32/config_H.vc ----------------------------------------------------------------------- Summary of changes: Configure | 270 +++++++++++++++++++++++ Cross/config.sh-arm-linux | 7 + NetWare/config.wc | 7 + NetWare/config_H.wc | 40 ++++ Porting/Glossary | 35 +++ Porting/config.sh | 7 + config_h.SH | 47 ++++ configure.com | 17 ++ ext/POSIX/POSIX.xs | 260 ++++++++++++++++++---- ext/POSIX/lib/POSIX.pm | 2 + ext/POSIX/lib/POSIX.pod | 87 +++++++- ext/POSIX/t/export.t | 4 + ext/POSIX/t/math.t | 82 ++++++- globvar.sym | 2 + perl.h | 537 ++++++++++++++++++++++++++++++++++++++-------- plan9/config_sh.sample | 7 + symbian/config.sh | 7 + uconfig.h | 51 ++++- uconfig.sh | 7 + uconfig64.sh | 7 + win32/config.ce | 7 + win32/config.gc | 7 + win32/config.vc | 7 + win32/config_H.ce | 40 ++++ win32/config_H.gc | 40 ++++ win32/config_H.vc | 40 ++++ 26 files changed, 1475 insertions(+), 149 deletions(-) diff --git a/Configure b/Configure index 0a405d3..ef22432 100755 --- a/Configure +++ b/Configure @@ -631,7 +631,10 @@ d_log2='' d_logb='' d_ldexpl='' d_longdbl='' +longdblinfbytes='' longdblkind='' +longdblmantbits='' +longdblnanbytes='' longdblsize='' d_longlong='' longlongsize='' @@ -1096,6 +1099,9 @@ d_PRIfldbl='' d_PRIgldbl='' d_SCNfldbl='' doublekind='' +doubleinfbytes='' +doublemantbits='' +doublenanbytes='' sPRIEUldbl='' sPRIFUldbl='' sPRIGUldbl='' @@ -1174,6 +1180,7 @@ ivsize='' ivtype='' nv_overflows_integers_at='' nv_preserves_uv_bits='' +nvmantbits='' nvsize='' nvtype='' u16size='' @@ -10114,6 +10121,174 @@ case "$doublekind" in esac $rm_try +: see if this is a math.h system +set math.h i_math +eval $inhdr + +: Check what kind of inf/nan your system has +$echo "Checking the kind of infinities and nans you have..." >&4 +$cat >try.c <<EOP +#define DOUBLESIZE $doublesize +#$d_longdbl HAS_LONG_DOUBLE +#ifdef HAS_LONG_DOUBLE +#define LONGDBLSIZE $longdblsize +#define LONGDBLKIND $longdblkind +#endif +#$i_math I_MATH +#ifdef I_MATH +#include <math.h> +#endif +#include <stdio.h> +/* Note that whether the sign bit is on or off + * for NaN depends on the CPU/FPU, and possibly + * can be affected by the build toolchain. + * + * For example for older MIPS and HP-PA 2.0 the quiet NaN is: + * 0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + * 0x7f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + * (respectively) as opposed to the more usual + * 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + */ +static void bytes(unsigned char *p, unsigned int n) { + int i; + for (i = 0; i < n; i++) { + printf("0x%02x%s", p[i], i < n - 1 ? ", " : "\n"); + } +} +int main(int argc, char *argv[]) { + /* We cannot use 1.0/0.0 and 0.0/0.0 (with L suffixes for long double) + * because some compilers are 'smart' and not only warn but refuse to + * compile such 'illegal' values. */ + double dinf = exp(1e9); + double dnan = sqrt(-1.0); +#ifdef HAS_LONG_DOUBLE + long double ldinf = (long double)exp(1e9); + long double ldnan = (long double)sqrt(-1.0); +#endif + if (argc == 2) { + switch (argv[1][0]) { + case '1': bytes(&dinf, sizeof(dinf)); break; + case '2': bytes(&dnan, sizeof(dnan)); break; +#ifdef HAS_LONG_DOUBLE +# if LONG_DOUBLEKIND == 3 || LONG_DOUBLEKIND == 4 +/* the 80-bit long doubles might have garbage in their excess bytes */ + memset((char *)&ldinf + 10, '\0', LONG_DOUBLESIZE - 10); +# endif + case '3': bytes(&ldinf, sizeof(ldinf)); break; + case '4': bytes(&ldnan, sizeof(ldnan)); break; +#endif + } + } + return 0; +} +EOP +set try +if eval $compile; then + doubleinfbytes=`$run ./try 1` + doublenanbytes=`$run ./try 2` + case "$d_longdbl" in + $define) + longdblinfbytes=`$run ./try 3` + longdblnanbytes=`$run ./try 4` + ;; + esac +else + # Defaults in case the above test program failed. + case "$doublekind" in + 1) # IEEE 754 32-bit LE + doubleinfbytes='0x00, 0x00, 0xf0, 0x7f' + doublenanbytes='0x00, 0x00, 0xf8, 0x7f' + ;; + 2) # IEEE 754 32-bit BE + doubleinfbytes='0x7f, 0xf0, 0x00, 0x00' + doublenanbytes='0x7f, 0xf8, 0x00, 0x00' + ;; + 3) # IEEE 754 64-bit LE + doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' + doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' + ;; + 4) # IEEE 754 64-bit BE + doubleinfbytes='0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + doublenanbytes='0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + 5) # IEEE 754 128-bit LE + doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' + doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' + ;; + 6) # IEEE 754 128-bit BE + doubleinfbytes='0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + doublenanbytes='0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + 7) # IEEE 754 64-bit mixed: 32-bit LEs in BE + doubleinfbytes='0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00' + doublenanbytes='0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00' + ;; + 8) # IEEE 754 64-bit mixed: 32-bit BEs in LE + doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00' + doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00' + ;; + *) # No idea. + doubleinfbytes=$undef + doublenanbytes=$undef + ;; + esac + case "$longdblkind" in + 1) # IEEE 754 128-bit LE + longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f' + longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f' + ;; + 2) # IEEE 754 128-bit BE + longdblinfbytes='0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + longdblnanbytes='0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + 3) # IEEE 754 80-bit LE, 12 or 16 bytes (x86) + case "$longdblsize" in + 12) # x86 32-bit (96 bits, or 4 x 32, or 12 x 8) + longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00' + longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00' + ;; + 16) # x86_64 + longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + *) # No idea. + longdblinfbytes=$undef + longdlnan=$undef + ;; + esac + ;; + 4) # IEEE 754 80-bit BE, 12 or 16 bytes + case "$longdblsize" in + 12) # 32-bit system + longdblinfbytes='0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + longdblnanbytes='0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + 16) # 64-bit system + longdblinfbytes='0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + longdblnanbytes='0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + *) # No idea. + longdblinfbytes=$undef + longdlnan=$undef + ;; + esac + ;; + 5) # 128-bit LE "double double" + longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' + longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' + ;; + 6) # 128-bit BE "double double" + longdblinfbytes='0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + longdblnanbytes='0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' + ;; + *) # No idea. + longdblinfbytes=$undef + longdlnan=$undef + ;; + esac +fi +$rm_try + : Check print/scan long double stuff echo " " @@ -18587,6 +18762,94 @@ set d_signbit eval $setvar $rm_try +$echo "Checking how many mantissa bits your doubles have..." >&4 +$cat >try.c <<EOP +#$i_float I_FLOAT +#$i_sunmath I_SUNMATH +#ifdef I_FLOAT +# include <float.h> +#endif +#ifdef I_SUNMATH +# include <sunmath.h> +#endif +#ifdef DBL_MANT_DIG +# define BITS (DBL_MANT_DIG - 1) /* the implicit bit does not count */ +#endif +#include <stdio.h> +int main(int argc, char *argv[]) { +#ifdef BITS + printf("%d\n", BITS); +#endif + return 0; +} +EOP +set try +if eval $compile; then + doublemantbits=`$run ./try` +else + doublemantbits="$undef" +fi +$rm_try + +$echo "Checking how many mantissa bits your long doubles have..." >&4 +$cat >try.c <<EOP +#$i_float I_FLOAT +#$i_sunmath I_SUNMATH +#ifdef I_FLOAT +# include <float.h> +#endif +#ifdef I_SUNMATH +# include <sunmath.h> +#endif +#$d_longdbl HAS_LONG_DOUBLE +#if defined(HAS_LONG_DOUBLE) && defined(LDBL_MANT_DIG) +# if ($longdblkind == 3) || ($longdblkind == 4) /* 80-bit extended precision */ +/* This format has no implicit bit. Beware, however, that for + * this format the bare LDBL_MANT_DIG is misleading for inf/nan: + * the top three bits are used for inf (100) / qnan (11x) / snan (101), + * and the top bit must have been one since 387, zero is plain invalid. + * For normal fp values, the LDBL_MANT_DIG is fine, though. */ +# define BITS LDBL_MANT_DIG +# elif ($longdblkind == 5 || $longdblkind == 6) /* double double */ +/* LDBL_MANT_DIG of 106 (twice 53) would be logical, but for some + * reason e.g. Irix thinks 107. But in any case, we want only + * the number of real bits, the implicit bits are of no interest. */ +# define BITS 2 * (DBL_MANT_DIG - 1) +# else +# define BITS (LDBL_MANT_DIG - 1) /* the implicit bit does not count */ +# endif +#endif +#include <stdio.h> +int main(int argc, char *argv[]) { +#ifdef BITS + printf("%d\n", BITS); +#endif + return 0; +} +EOP +set try +if eval $compile; then + longdblmantbits=`$run ./try` +else + longdblmantbits="$undef" +fi +$rm_try + +$echo "Checking how many mantissa bits your NVs have..." >&4 +if test "X$usequadmath" = "X$define"; then + nvmantbits=112 # 128-1-15 +else + if test "X$nvsize" = "X$doublesize"; then + nvmantbits="$doublemantbits" + else + if test "X$nvsize" = "X$longdblsize"; then + nvmantbits="$longdblmantbits" + else + nvmantbits="$undef" + fi + fi +fi + : see if sigprocmask exists set sigprocmask d_sigprocmask eval $inlibc @@ -24286,7 +24549,10 @@ db_version_patch='$db_version_patch' direntrytype='$direntrytype' dlext='$dlext' dlsrc='$dlsrc' +doubleinfbytes='$doubleinfbytes' doublekind='$doublekind' +doublemantbits='$doublemantbits' +doublenanbytes='$doublenanbytes' doublesize='$doublesize' drand01='$drand01' drand48_r_proto='$drand48_r_proto' @@ -24534,7 +24800,10 @@ lns='$lns' localtime_r_proto='$localtime_r_proto' locincpth='$locincpth' loclibpth='$loclibpth' +longdblinfbytes='$longdblinfbytes' longdblkind='$longdblkind' +longdblmantbits='$longdblmantbits' +longdblnanbytes='$longdblnanbytes' longdblsize='$longdblsize' longlongsize='$longlongsize' longsize='$longsize' @@ -24587,6 +24856,7 @@ nv_preserves_uv_bits='$nv_preserves_uv_bits' nveformat='$nveformat' nvfformat='$nvfformat' nvgformat='$nvgformat' +nvmantbits='$nvmantbits' nvsize='$nvsize' nvtype='$nvtype' o_nonblock='$o_nonblock' diff --git a/Cross/config.sh-arm-linux b/Cross/config.sh-arm-linux index 6efcb43..3d1eb4d 100644 --- a/Cross/config.sh-arm-linux +++ b/Cross/config.sh-arm-linux @@ -612,7 +612,10 @@ db_version_patch='' direntrytype='struct dirent' dlext='so' dlsrc='dl_dlopen.xs' +doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' doublekind='3' +doublemantbits='52' +doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' doublesize='8' drand01='Perl_drand48()' drand48_r_proto='0' @@ -853,7 +856,10 @@ lns='/bin/ln -s' localtime_r_proto='0' locincpth='/usr/local/include /opt/local/include /usr/gnu/include /opt/gnu/include /usr/GNU/include /opt/GNU/include' loclibpth='/usr/local/lib /opt/local/lib /usr/gnu/lib /opt/gnu/lib /usr/GNU/lib /opt/GNU/lib' +longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblkind='0' +longdblmantbits='64' +longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblsize='8' longlongsize='8' longsize='4' @@ -907,6 +913,7 @@ nv_preserves_uv_bits='32' nveformat='"e"' nvfformat='"f"' nvgformat='"g"' +nvmantbits='52' nvsize='8' nvtype='double' o_nonblock='O_NONBLOCK' diff --git a/NetWare/config.wc b/NetWare/config.wc index 68df99e..e70b4df 100644 --- a/NetWare/config.wc +++ b/NetWare/config.wc @@ -603,7 +603,10 @@ def_temp='sys:\perl\temp' direntrytype='DIR' dlext='nlm' dlsrc='dl_netware.xs' +doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' doublekind='3' +doublemantbits='52' +doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' doublesize='8' drand01='Perl_drand48()' drand48_r_proto='0' @@ -827,7 +830,10 @@ lns='copy' localtime_r_proto='0' locincpth='/usr/local/include /opt/local/include /usr/gnu/include /opt/gnu/include /usr/GNU/include /opt/GNU/include' loclibpth='/usr/local/lib /opt/local/lib /usr/gnu/lib /opt/gnu/lib /usr/GNU/lib /opt/GNU/lib' +longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f' longdblkind='3' +longdblmantbits='64' +longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblsize='10' longlongsize='8' longsize='4' @@ -882,6 +888,7 @@ nv_preserves_uv_bits='32' nveformat='"e"' nvfformat='"f"' nvgformat='"g"' +nvmantbits='52' nvsize='8' nvtype='double' o_nonblock='O_NONBLOCK' diff --git a/NetWare/config_H.wc b/NetWare/config_H.wc index 65c7211..4ebd1a0 100644 --- a/NetWare/config_H.wc +++ b/NetWare/config_H.wc @@ -2333,6 +2333,46 @@ */ #define DOUBLESIZE 8 /**/ +/* DOUBLEINFBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes for the double precision infinity. + */ +/* DOUBLENANBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes (0xHH) for the double precision not-a-number. + */ +/* LONGDBLINFBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes for the long double precision infinity. + */ +/* LONGDBLNANBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes (0xHH) for the long double precision not-a-number. + */ +#define DOUBLEINFBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f /**/ +#define DOUBLENANBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f /**/ +#define LONGDBLINFBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f /**/ +#define LONGDBLNANBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f /**/ + +/* DOUBLEMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * there are in double precision floating point format. + * Note that this is usually DBL_MANT_DIG minus one, since + * with the standard IEEE 754 formats DBL_MANT_DIG includes + * the implicit bit, which doesn't really exist. + */ +#define DOUBLEMANTBITS 52 + +/* LONGDBLMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * there are in long double precision floating point format. + * Note that this can be LDBL_MANT_DIG minus one, + * since LDBL_MANT_DIG can include the IEEE 754 implicit bit. + * The common x86-style 80-bit long double does not have + * an implicit bit. + */ +#define LONGDBLMANTBITS 52 + /* EBCDIC: * This symbol, if defined, indicates that this system uses * EBCDIC encoding. diff --git a/Porting/Glossary b/Porting/Glossary index 3f9057e..2cd4bb3 100644 --- a/Porting/Glossary +++ b/Porting/Glossary @@ -2840,6 +2840,10 @@ dlsrc (dlsrc.U): This variable contains the name of the dynamic loading file that will be used with the package. +doubleinfbytes (infnan.U): + This variable contains comma-separated list of hexadecimal bytes + for the double precision infinity. + doublekind (longdblfio.U): This variable, if defined, encodes the type of a double: 1 = IEEE 754 32-bit big little endian, @@ -2852,6 +2856,17 @@ doublekind (longdblfio.U): 8 = IEEE 754 64-bit big mixed endian be-le, -1 = unknown format. +doublemantbits (mantbits.U): + This symbol, if defined, tells how many mantissa bits + there are in double precision floating point format. + Note that this is usually DBL_MANT_DIG minus one, since + with the standard IEEE 754 formats DBL_MANT_DIG includes + the implicit bit which doesn't really exist. + +doublenanbytes (infnan.U): + This variable contains comma-separated list of hexadecimal bytes + for the double precision not-a-number. + doublesize (doublesize.U): This variable contains the value of the DOUBLESIZE symbol, which indicates to the C program how many bytes there are in a double. @@ -4076,6 +4091,10 @@ loclibpth (libpth.U): libraries. It is prepended to libpth, and is intended to be easily set from the command line. +longdblinfbytes (infnan.U): + This variable contains comma-separated list of hexadecimal bytes + for the long double precision infinity. + longdblkind (d_longdbl.U): This variable, if defined, encodes the type of a long double: 0 = double, 1 = IEEE 754 128-bit big little endian, @@ -4083,6 +4102,18 @@ longdblkind (d_longdbl.U): 4 = x86 80-bit big endian, 5 = double-double 128-bit little endian, 6 = double-double 128-bit big endian, -1 = unknown format. +longdblmantbits (longdblmant.U): + This symbol, if defined, tells how many mantissa bits + there are in long double precision floating point format. + Note that this can be LDBL_MANT_DIG minus one, + since LDBL_MANT_DIG can include the IEEE 754 implicit bit. + The common x86-style 80-bit long double does not have + an implicit bit. + +longdblnanbytes (infnan.U): + This variable contains comma-separated list of hexadecimal bytes + for the long double precision not-a-number. + longdblsize (d_longdbl.U): This variable contains the value of the LONG_DOUBLESIZE symbol, which indicates to the C program how many bytes there are in a long double, @@ -4351,6 +4382,10 @@ nvGUformat (perlxvf.U): This variable contains the format string used for printing a Perl NV using %G-ish floating point format. +nvmantbits (mantbits.U): + This variable tells how many bits the mantissa of a Perl NV has, + not including the possible implicit bit. + nvsize (perlxv.U): This variable is the size of a Perl NV in bytes. Note that some floating point formats have unused bytes. diff --git a/Porting/config.sh b/Porting/config.sh index e307147..93b2a6c 100644 --- a/Porting/config.sh +++ b/Porting/config.sh @@ -623,7 +623,10 @@ db_version_patch='30' direntrytype='struct dirent' dlext='so' dlsrc='dl_dlopen.xs' +doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' doublekind='3' +doublemantbits='52' +doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' doublesize='8' drand01='Perl_drand48()' drand48_r_proto='0' @@ -871,7 +874,10 @@ lns='/usr/bin/ln -s' localtime_r_proto='0' locincpth='/pro/local/include' loclibpth='/pro/local/lib' +longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblkind='3' +longdblmantbits='64' +longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblsize='12' longlongsize='8' longsize='4' @@ -925,6 +931,7 @@ nv_preserves_uv_bits='53' nveformat='"e"' nvfformat='"f"' nvgformat='"g"' +nvmantbits='52' nvsize='8' nvtype='double' o_nonblock='O_NONBLOCK' diff --git a/config_h.SH b/config_h.SH index fb2224e..0701a42 100755 --- a/config_h.SH +++ b/config_h.SH @@ -4837,6 +4837,53 @@ sed <<!GROK!THIS! >$CONFIG_H -e 's!^#undef\(.*/\)\*!/\*#define\1 \*!' -e 's!^#un #$d_PRIeldbl PERL_PRIeldbl $sPRIeldbl /**/ #$d_SCNfldbl PERL_SCNfldbl $sSCNfldbl /**/ +/* DOUBLEINFBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes for the double precision infinity. + */ +/* DOUBLENANBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes (0xHH) for the double precision not-a-number. + */ +/* LONGDBLINFBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes for the long double precision infinity. + */ +/* LONGDBLNANBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes (0xHH) for the long double precision not-a-number. + */ +#define DOUBLEINFBYTES $doubleinfbytes /**/ +#define DOUBLENANBYTES $doublenanbytes /**/ +#define LONGDBLINFBYTES $longdblinfbytes /**/ +#define LONGDBLNANBYTES $longdblnanbytes /**/ + +/* DOUBLEMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * there are in double precision floating point format. + * Note that this is usually DBL_MANT_DIG minus one, since + * with the standard IEEE 754 formats DBL_MANT_DIG includes + * the implicit bit, which doesn't really exist. + */ +#define DOUBLEMANTBITS $doublemantbits + +/* LONGDBLMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * there are in long double precision floating point format. + * Note that this can be LDBL_MANT_DIG minus one, + * since LDBL_MANT_DIG can include the IEEE 754 implicit bit. + * The common x86-style 80-bit long double does not have + * an implicit bit. + */ +#define LONGDBLMANTBITS $longdblmantbits + +/* NVMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * (not including implicit bit) there are in a Perl NV. + * This depends on which floating point type was chosen. + */ +#define NVMANTBITS $nvmantbits /**/ + /* NEED_VA_COPY: * This symbol, if defined, indicates that the system stores * the variable argument list datatype, va_list, in a format diff --git a/configure.com b/configure.com index bd05113..a136a77 100644 --- a/configure.com +++ b/configure.com @@ -3661,6 +3661,9 @@ $ IF link_status .NE. good_link $ THEN $ longdblsize="0" $ longdblkind="0" +$ longdblinfbytes="undef" +$ longdblnanbytes="undef" +$ longdblmantbits="undef" $ d_longdbl="undef" $ echo "You do not have long double." $ ELSE @@ -3669,6 +3672,9 @@ $ echo4 "Checking to see how big your long doubles are..." $ GOSUB just_mcr_it $ longdblsize = tmp $ longdblkind = "1" +$ longdblinfbytes="0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f" +$ longdblnanbytes="0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff" +$ longdblmantbits="112" $ d_longdbl = "define" $ echo "Your long doubles are ''longdblsize' bytes long." $ ENDIF @@ -5569,9 +5575,13 @@ $ i64size="undef" $ u64size="undef" $ ENDIF $! +$ doublemantbits = "52" $ IF uselongdouble .OR. uselongdouble .EQS. "define" $ THEN $ nvtype="long double" +$ nvmantbits = longdblmantbits +$ ELSE +$ nvmantbits = doublemantbits $ ENDIF $! $ tmp = "''ivtype'" @@ -6472,6 +6482,9 @@ $ WC "dlext='" + dlext + "'" $ WC "dlobj='" + dlobj + "'" $ WC "dlsrc='dl_vms.xs'" $ WC "doublekind='3'" +$ WC "doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f'" +$ WC "doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f'" +$ WC "doublemantbits='" + doublemantbits + "'" $ WC "doublesize='" + doublesize + "'" $ WC "drand01='" + drand01 + "'" $ WC "dtrace='" + "'" @@ -6648,6 +6661,9 @@ $ WC "libswanted='" + "'" $ WC "libswanted_uselargefiles='" + "'" $ WC "longdblsize='" + longdblsize + "'" $ WC "longdblkind='" + longdblkind + "'" +$ WC "longdblinfbytes='" + longdblinfbytes + "'" +$ WC "longdblnanbytes='" + longdblnanbytes + "'" +$ WC "longdblmantbits='" + longdblmantbits + "'" $ WC "longlongsize='" + longlongsize + "'" $ WC "longsize='" + longsize + "'" $ IF uselargefiles .OR. uselargefiles .EQS. "define" @@ -6683,6 +6699,7 @@ $ WC "nvfformat='" + nvfformat + "'" $ WC "nvFUformat='" + nvFUformat + "'" $ WC "nvgformat='" + nvgformat + "'" $ WC "nvGUformat='" + nvGUformat + "'" +$ WC "nvmantbits='" + nvmantbits + "'" $ WC "nvsize='" + nvsize + "'" $ WC "nvtype='" + nvtype + "'" $ WC "o_nonblock=' '" diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs index 535fccf..670d8ec 100644 --- a/ext/POSIX/POSIX.xs +++ b/ext/POSIX/POSIX.xs @@ -1118,6 +1118,167 @@ static NV my_trunc(NV x) # define c99_trunc my_trunc #endif +#undef NV_PAYLOAD_DEBUG + +/* NOTE: the NaN payload API implementation is hand-rolled, since the + * APIs are only proposed ones as of June 2015, so very few, if any, + * platforms have implementations yet, so HAS_SETPAYLOAD and such are + * unlikely to be helpful. + * + * XXX - if the core numification wants to actually generate + * the nan payload in "nan(123)", and maybe "nans(456)", for + * signaling payload", this needs to be moved to e.g. numeric.c + * (look for grok_infnan) + * + * Conversely, if the core stringification wants the nan payload + * and/or the nan quiet/signaling distinction, S_getpayload() + * from this file needs to be moved, to e.g. sv.c (look for S_infnan_2pv), + * and the (trivial) functionality of issignaling() copied + * (for generating "NaNS", or maybe even "NaNQ") -- or maybe there + * are too many formatting parameters for simple stringification? + */ + +/* While it might make sense for the payload to be UV or IV, + * to avoid conversion loss, the proposed ISO interfaces use + * a floating point input, which is then truncated to integer, + * and only the integer part being used. This is workable, + * except for: (1) the conversion loss (2) suboptimal for + * 32-bit integer platforms. A workaround API for (2) and + * in general for bit-honesty would be an array of integers + * as the payload... but the proposed C API does nothing of + * the kind. */ +#if NVSIZE == UVSIZE +# define NV_PAYLOAD_TYPE UV +#else +# define NV_PAYLOAD_TYPE NV +#endif + +#ifdef LONGDOUBLE_DOUBLEDOUBLE +# define NV_PAYLOAD_SIZEOF_ASSERT(a) assert(sizeof(a) == NVSIZE / 2) +#else +# define NV_PAYLOAD_SIZEOF_ASSERT(a) assert(sizeof(a) == NVSIZE) +#endif + +static void S_setpayload(NV* nvp, NV_PAYLOAD_TYPE payload, bool signaling) +{ + dTHX; + static const U8 m[] = { NV_NAN_PAYLOAD_MASK }; + static const U8 p[] = { NV_NAN_PAYLOAD_PERM }; + UV a[(NVSIZE + UVSIZE - 1) / UVSIZE] = { 0 }; + int i; + NV_PAYLOAD_SIZEOF_ASSERT(m); + NV_PAYLOAD_SIZEOF_ASSERT(p); + *nvp = NV_NAN; + /* Divide the input into the array in "base unsigned integer" in + * little-endian order. Note that the integer might be smaller than + * an NV (if UV is U32, for example). */ +#if NVSIZE == UVSIZE + a[0] = payload; /* The trivial case. */ +#else + { + NV t1 = c99_trunc(payload); /* towards zero (drop fractional) */ +#ifdef NV_PAYLOAD_DEBUG + Perl_warn(aTHX_ "t1 = %"NVgf" (payload %"NVgf")\n", t1, payload); +#endif + if (t1 <= UV_MAX) { + a[0] = (UV)t1; /* Fast path, also avoids rounding errors (right?) */ + } else { + /* UVSIZE < NVSIZE or payload > UV_MAX. + * + * This may happen for example if: + * (1) UVSIZE == 32 and common 64-bit double NV + * (32-bit system not using -Duse64bitint) + * (2) UVSIZE == 64 and the x86-style 80-bit long double NV + * (note that here the room for payload is actually the 64 bits) + * (3) UVSIZE == 64 and the 128-bit IEEE 764 quadruple NV + * (112 bits in mantissa, 111 bits room for payload) + * + * NOTE: this is very sensitive to correctly functioning + * fmod()/fmodl(), and correct casting of big-unsigned-integer to NV. + * If these don't work right, especially the low order bits + * are in danger. For example Solaris and AIX seem to have issues + * here, especially if using 32-bit UVs. */ + NV t2; + for (i = 0, t2 = t1; i < (int)C_ARRAY_LENGTH(a); i++) { + a[i] = (UV)Perl_fmod(t2, (NV)UV_MAX); + t2 = Perl_floor(t2 / (NV)UV_MAX); + } + } + } +#endif +#ifdef NV_PAYLOAD_DEBUG + for (i = 0; i < (int)C_ARRAY_LENGTH(a); i++) { + Perl_warn(aTHX_ "a[%d] = 0x%"UVxf"\n", i, a[i]); + } +#endif + for (i = 0; i < (int)sizeof(p); i++) { + if (m[i] && p[i] < sizeof(p)) { + U8 s = (p[i] % UVSIZE) << 3; + UV u = a[p[i] / UVSIZE] & ((UV)0xFF << s); + U8 b = (U8)((u >> s) & m[i]); + ((U8 *)(nvp))[i] &= ~m[i]; /* For NaNs with non-zero payload bits. */ + ((U8 *)(nvp))[i] |= b; +#ifdef NV_PAYLOAD_DEBUG + Perl_warn(aTHX_ "set p[%2d] = %02x (i = %d, m = %02x, s = %2d, b = %02x, u = %08"UVxf")\n", i, ((U8 *)(nvp))[i], i, m[i], s, b, u); +#endif + a[p[i] / UVSIZE] &= ~u; + } + } + if (signaling) { + NV_NAN_SET_SIGNALING(nvp); + } +#ifdef USE_LONG_DOUBLE +# if LONG_DOUBLEKIND == 3 || LONG_DOUBLEKIND == 4 + memset((char *)nvp + 10, '\0', LONG_DOUBLESIZE - 10); /* x86 long double */ +# endif +#endif + for (i = 0; i < (int)C_ARRAY_LENGTH(a); i++) { + if (a[i]) { + Perl_warn(aTHX_ "payload lost bits (%"UVxf")", a[i]); + break; + } + } +#ifdef NV_PAYLOAD_DEBUG + for (i = 0; i < NVSIZE; i++) { + PerlIO_printf(Perl_debug_log, "%02x ", ((U8 *)(nvp))[i]); + } + PerlIO_printf(Perl_debug_log, "\n"); +#endif +} + +static NV_PAYLOAD_TYPE S_getpayload(NV nv) +{ + dTHX; + static const U8 m[] = { NV_NAN_PAYLOAD_MASK }; + static const U8 p[] = { NV_NAN_PAYLOAD_PERM }; + UV a[(NVSIZE + UVSIZE - 1) / UVSIZE] = { 0 }; + int i; + NV payload; + NV_PAYLOAD_SIZEOF_ASSERT(m); + NV_PAYLOAD_SIZEOF_ASSERT(p); + payload = 0; + for (i = 0; i < (int)sizeof(p); i++) { + if (m[i] && p[i] < NVSIZE) { + U8 s = (p[i] % UVSIZE) << 3; + a[p[i] / UVSIZE] |= (UV)(((U8 *)(&nv))[i] & m[i]) << s; + } + } + for (i = (int)C_ARRAY_LENGTH(a) - 1; i >= 0; i--) { +#ifdef NV_PAYLOAD_DEBUG + Perl_warn(aTHX_ "a[%d] = %"UVxf"\n", i, a[i]); +#endif + payload *= UV_MAX; + payload += a[i]; + } +#ifdef NV_PAYLOAD_DEBUG + for (i = 0; i < NVSIZE; i++) { + PerlIO_printf(Perl_debug_log, "%02x ", ((U8 *)(&nv))[i]); + } + PerlIO_printf(Perl_debug_log, "\n"); +#endif + return payload; +} + /* XXX This comment is just to make I_TERMIO and I_SGTTY visible to metaconfig for future extension writers. We don't use them in POSIX. (This is really sneaky :-) --AD @@ -2508,6 +2669,41 @@ fpclassify(x) RETVAL NV +getpayload(nv) + NV nv + CODE: + RETVAL = S_getpayload(nv); + OUTPUT: + RETVAL + +void +setpayload(nv, payload) + NV nv + NV payload + CODE: + S_setpayload(&nv, payload, FALSE); + OUTPUT: + nv + +void +setpayloadsig(nv, payload) + NV nv + NV payload + CODE: + nv = NV_NAN; + S_setpayload(&nv, payload, TRUE); + OUTPUT: + nv + +int +issignaling(nv) + NV nv + CODE: + RETVAL = Perl_isnan(nv) && NV_NAN_IS_SIGNALING(&nv); + OUTPUT: + RETVAL + +NV copysign(x,y) NV x NV y @@ -2707,51 +2903,27 @@ fma(x,y,z) RETVAL NV -nan(s = 0) - char* s; +nan(payload = 0) + NV payload CODE: - PERL_UNUSED_VAR(s); -#ifdef c99_nan - RETVAL = c99_nan(s ? s : ""); -#elif defined(NV_NAN) - /* XXX if s != NULL, warn about unused argument, - * or implement the nan payload setting. */ - /* NVSIZE == 8: the NaN "header" (the exponent) is 0x7FF (the 0x800 - * is the sign bit, which should be irrelevant for NaN, so really - * also 0xFFF), leaving 64 - 12 = 52 bits for the NaN payload - * (6.5 bytes, note about infinities below). - * - * (USE_LONG_DOUBLE and) - * LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN: - * the NaN "header" is still 0x7FF, leaving 80 - 12 = 68 bits - * for the payload (8.5 bytes, note about infinities below). - * - * doubledouble? aargh. Maybe like doubles, 52 + 52 = 104 bits? - * - * NVSIZE == 16: - * the NaN "header" is still 0x7FF, leaving 128 - 12 = 116 bits - * for the payload (14.5 bytes, note about infinities below) - * - * Which ones of the NaNs are 'signaling' and which are 'quiet', - * depends. In the IEEE-754 1985, nothing was specified. But the - * majority of companies decided that the MSB of the mantissa was - * the bit for 'quiet'. (Only PA-RISC and MIPS were different, - * using the MSB as 'signaling'.) The IEEE-754 2008 *recommended* - * (but did not dictate) the MSB as the 'quiet' bit. - * - * In other words, on most platforms, and for 64-bit doubles: - * [7FF8000000000000, 7FFFFFFFFFFFFFFF] quiet - * [FFF8000000000000, FFFFFFFFFFFFFFFF] quiet - * [7FF0000000000001, 7FF7FFFFFFFFFFFF] signaling - * [FFF0000000000001, FFF7FFFFFFFFFFFF] signaling - * - * The C99 nan() is supposed to generate *quiet* NaNs. - * - * Note the asymmetry: - * The 7FF0000000000000 is positive infinity, - * the FFF0000000000000 is negative infinity. - */ - RETVAL = NV_NAN; +#ifdef NV_NAN + /* If no payload given, just return the default NaN. + * This makes a difference in platforms where the default + * NaN is not all zeros. */ + if (items == 0) { + RETVAL = NV_NAN; + } else { + S_setpayload(&RETVAL, payload, FALSE); + } +#elif defined(c99_nan) + { + STRLEN elen = my_snprintf(PL_efloatbuf, PL_efloatsize, "%g", nv); + if ((IV)elen == -1) { + RETVAL = NV_NAN; + } else { + RETVAL = c99_nan(PL_efloatbuf); + } + } #else not_here("nan"); #endif diff --git a/ext/POSIX/lib/POSIX.pm b/ext/POSIX/lib/POSIX.pm index 15eb5d6..215b1f5 100644 --- a/ext/POSIX/lib/POSIX.pm +++ b/ext/POSIX/lib/POSIX.pm @@ -403,6 +403,8 @@ my %other_export_tags = ( )], stdlib_h_c99 => [ @{$default_export_tags{stdlib_h}}, 'strtold' ], + + nan_payload => [ qw(getpayload setpayload setpayloadsig issignaling) ], ); { diff --git a/ext/POSIX/lib/POSIX.pod b/ext/POSIX/lib/POSIX.pod index d9e84b4..3e6f78d 100644 --- a/ext/POSIX/lib/POSIX.pod +++ b/ext/POSIX/lib/POSIX.pod @@ -626,6 +626,17 @@ This is identical to Perl's builtin C<getlogin()> function for returning the user name associated with the current session, see L<perlfunc/getlogin>. +=item C<getpayload> + + use POSIX ':nan_payload'; + getpayload($var) + +Returns the C<NaN> payload. + +Note the API instability warning in L</setpayload>. + +See L</nan> for more discussion about C<NaN>. + =item C<getpgrp> This is identical to Perl's builtin C<getpgrp()> function for @@ -867,6 +878,17 @@ modifier is in effect?>). The function returns C<TRUE> if the input string is empty, or if the corresponding C function returns C<TRUE> for every byte in the string. +=item C<issignaling> + + use POSIX ':nan_payload'; + issignaling($var, $payload) + +Return true if the argument is a I<signaling> NaN. + +Note the API instability warning in L</setpayload>. + +See L</nan> for more discussion about C<NaN>. + =item C<isspace> Deprecated function whose use raises a warning, and which is slated to @@ -1193,9 +1215,38 @@ See also L</round>. =item C<nan> -Returns not-a-number [C99]. + my $nan = nan(); + +Returns C<NaN>, not-a-number [C99]. + +The returned NaN is always a I<quiet> NaN, as opposed to I<signaling>. + +With an argument, can be used to generate a NaN with I<payload>. +The argument is first interpreted as a floating point number, +but then any fractional parts are truncated (towards zero), +and the value is interpreted as an unsigned integer. +The bits of this integer are stored in the unused bits of the NaN. + +The result has a dual nature: it is a NaN, but it also carries +the integer inside it. The integer can be retrieved with L</getpayload>. +Note, though, that the payload is not propagated, not even on copies, +and definitely not in arithmetic operations. + +How many bits fit in the NaN depends on what kind of floating points +are being used, but on the most common platforms (64-bit IEEE 754, +or the x86 80-bit long doubles) there are 51 and 61 bits available, +respectively. (There would be 52 and 62, but the quiet/signaling +bit of NaNs takes away one.) However, because of the floating-point-to- +integer-and-back conversions, please test carefully whether you get back +what you put in. If your integers are only 32 bits wide, you probably +should not rely on more than 32 bits of payload. -See also L</isnan>. +Whether a "signaling" NaN is in any way different from a "quiet" NaN, +depends on the platform. Also note that the payload of the default +NaN (no argument to nan()) is not necessarily zero, use C<setpayload> +to explicitly set the payload. + +See also L</isnan>, L</setpayload> and L</issignaling>. =item C<nearbyint> @@ -1489,6 +1540,38 @@ out which locales are available in your system. $loc = setlocale( LC_COLLATE, "es_AR.ISO8859-1" ); +=item C<setpayload> + + use POSIX ':nan_payload'; + setpayload($var, $payload); + +Sets the C<NaN> payload of var. + +NOTE: the NaN payload APIs are based on the latest (as of June 2015) +proposed ISO C interfaces, but they are not yet a standard. Things +may change. + +See L</nan> for more discussion about C<NaN>. + +See also L</setpayloadsig>, L</isnan>, L</getpayload>, and L</issignaling>. + +=item C<setpayloadsig> + + use POSIX ':nan_payload'; + setpayloadsig($var, $payload); + +Like L</setpayload> but also makes the NaN I<signaling>. + +Depending on the platform the NaN may or may not behave differently. + +Note the API instability warning in L</setpayload>. + +Note that because how the floating point formats work out, on the most +common platforms signaling payload of zero is best avoided, +since it might end up being identical to C<+Inf>. + +See also L</nan>, L</isnan>, L</getpayload>, and L</issignaling>. + =item C<setpgid> This is similar to the C function C<setpgid()> for diff --git a/ext/POSIX/t/export.t b/ext/POSIX/t/export.t index 91593e0..553a8a9 100644 --- a/ext/POSIX/t/export.t +++ b/ext/POSIX/t/export.t @@ -138,6 +138,10 @@ my %expect = ( nearbyint nextafter nexttoward remainder remquo rint round scalbn signbit tgamma trunc y0 y1 yn strtold ), + # this stuff was added in 5.23 + qw( + getpayload issignaling setpayload setpayloadsig + ), ], ); diff --git a/ext/POSIX/t/math.t b/ext/POSIX/t/math.t index 7e70753..027f8ed 100644 --- a/ext/POSIX/t/math.t +++ b/ext/POSIX/t/math.t @@ -3,6 +3,7 @@ use strict; use POSIX ':math_h_c99'; +use POSIX ':nan_payload'; use Test::More; use Config; @@ -69,13 +70,11 @@ sub near { } SKIP: { - my $C99_SKIP = 59; - unless ($Config{d_acosh}) { - skip "no acosh, suspecting no C99 math", $C99_SKIP; + skip "no acosh, suspecting no C99 math"; } if ($^O =~ /Win32|VMS/) { - skip "running in $^O, C99 math support uneven", $C99_SKIP; + skip "running in $^O, C99 math support uneven"; } near(M_SQRT2, 1.4142135623731, "M_SQRT2", 1e-9); near(M_E, 2.71828182845905, "M_E", 1e-9); @@ -137,8 +136,79 @@ SKIP: { near(tgamma(9), 40320, "tgamma 9", 1.5e-7); near(lgamma(9), 10.6046029027452, "lgamma 9", 1.5e-7); - # If adding more tests here, update also the $C99_SKIP - # at the beginning of this SKIP block. + # These don't work on old mips/hppa platforms because == Inf (or == -Inf). + # ok(isnan(setpayload(0)), "setpayload zero"); + # is(getpayload(setpayload(0)), 0, "setpayload + getpayload (zero)"); + # + # These don't work on most platforms because == Inf (or == -Inf). + # ok(isnan(setpayloadsig(0)), "setpayload zero"); + # is(getpayload(setpayloadsig(0)), 0, "setpayload + getpayload (zero)"); + + # Verify that the payload set be setpayload() + # (1) still is a nan + # (2) but the payload can be retrieved + # (3) but is not signaling + my $x = 0; + setpayload($x, 0x12345); + ok(isnan($x), "setpayload + isnan"); + is(getpayload($x), 0x12345, "setpayload + getpayload"); + ok(!issignaling($x), "setpayload + issignaling"); + + # Verify that the signaling payload set be setpayloadsig() + # (1) still is a nan + # (2) but the payload can be retrieved + # (3) and is signaling + setpayloadsig($x, 0x12345); + ok(isnan($x), "setpayloadsig + isnan"); + is(getpayload($x), 0x12345, "setpayload + getpayload"); + ok(issignaling($x), "setpayloadsig + issignaling"); + + # Try a payload more than one byte. + is(getpayload(nan(0x12345)), 0x12345, "nan + getpayload"); + + # Try payloads of 2^k, most importantly at and beyond 2^32. These + # tests will fail if NV is just 32-bit float, but that Should Not + # Happen (tm). + is(getpayload(nan(2**31)), 2**31, "nan + getpayload 2**31"); + is(getpayload(nan(2**32)), 2**32, "nan + getpayload 2**32"); + is(getpayload(nan(2**33)), 2**33, "nan + getpayload 2**33"); + + # Payloads just lower than 2^k. + is(getpayload(nan(2**31-1)), 2**31-1, "nan + getpayload 2**31-1"); + is(getpayload(nan(2**32-1)), 2**32-1, "nan + getpayload 2**32-1"); + + # Payloads not divisible by two (and larger than 2**32). + + SKIP: { + # solaris gets 10460353202 from getpayload() when it should + # get 10460353203 (the 3**21). Things go wrong already in + # the nan() payload setting: [0x2, 0x6f7c52b4] (ivsize=4) + # instead [0x2, 0x6f7c52b3]. Then at getpayload() things + # go wrong again, now in other direction: with the (wrong) + # [0x2, 0x6f7c52b4] encoded in the nan we should decode into + # 10460353204, but we get 10460353202. It doesn't seem to + # help even if we use 'unsigned long long' instead of UV/U32 + # in the POSIX.xs:S_setpayload/S_getpayload. + # + # casting bug? fmod() bug? Though also broken with + # -Duselongdouble + fmodl(), so maybe Solaris cc bug + # in general? + # + # Ironically, the large prime seems to work even in Solaris, + # probably just by blind luck. + skip($^O, 1) if $^O eq 'solaris'; + is(getpayload(nan(3**21)), 3**21, "nan + getpayload 3**21"); + } + is(getpayload(nan(4294967311)), 4294967311, "nan + getpayload prime"); + + # Truncates towards zero. + is(getpayload(nan(1234.567)), 1234, "nan (trunc) + getpayload"); + + # Not signaling. + ok(!issignaling(0), "issignaling zero"); + ok(!issignaling(+Inf), "issignaling +Inf"); + ok(!issignaling(-Inf), "issignaling -Inf"); + ok(!issignaling(NaN), "issignaling NaN"); } # SKIP done_testing(); diff --git a/globvar.sym b/globvar.sym index 87059e2..1183d67 100644 --- a/globvar.sym +++ b/globvar.sym @@ -15,6 +15,7 @@ PL_fold_locale PL_freq PL_global_struct_size PL_hexdigit +PL_inf PL_interp_size PL_interp_size_5_18_0 PL_keyword_plugin @@ -24,6 +25,7 @@ PL_magic_vtable_names PL_magic_vtables PL_memory_wrap PL_mod_latin1_uc +PL_nan PL_no_aelem PL_no_dir_func PL_no_func diff --git a/perl.h b/perl.h index be9fc9a..2867c7a 100644 --- a/perl.h +++ b/perl.h @@ -1974,8 +1974,6 @@ extern long double Perl_my_frexpl(long double x, int *e); # define NV_EPSILON FLT128_EPSILON # define NV_MIN_10_EXP FLT128_MIN_10_EXP # define NV_MAX_10_EXP FLT128_MAX_10_EXP -# define NV_INF HUGE_VALQ -# define NV_NAN nanq("0") # define Perl_acos acosq # define Perl_asin asinq # define Perl_atan atanq @@ -4293,98 +4291,6 @@ START_EXTERN_C END_EXTERN_C #endif -/* If you are thinking of using HUGE_VAL for infinity, or using - * <math.h> functions to generate NV_INF (e.g. exp(1e9), log(-1.0)), - * stop. Neither will work portably: HUGE_VAL can be just DBL_MAX, - * and the math functions might be just generating DBL_MAX, or even - * zero. */ - -#if !defined(NV_INF) && defined(USE_LONG_DOUBLE) -# if !defined(NV_INF) && defined(LDBL_INFINITY) -# define NV_INF LDBL_INFINITY -# endif -# if !defined(NV_INF) && defined(INFINITYL) -# define NV_INF INFINITYL -# endif -#endif -#if !defined(NV_INF) && defined(DBL_INFINITY) -# define NV_INF (NV)DBL_INFINITY -#endif -#if !defined(NV_INF) && defined(INFINITY) -# define NV_INF (NV)INFINITY -#endif -#if !defined(NV_INF) && defined(INF) -# define NV_INF (NV)INF -#endif -#if !defined(NV_INF) -# if INTSIZE == 4 -/* At this point we assume the IEEE 754 floating point (and of course, - * we also assume a floating point format that can encode an infinity). - * We will coerce an int32 (which will encode the infinity) into - * a 32-bit float, which will then be cast into NV. - * - * Note that we intentionally use a float and 32-bit int, instead of - * shifting a small integer into a full IV, and from that into a full - * NV, because: - * - * (1) an IV might not be wide enough to cover all the bits of an NV. - * (2) the exponent part (including the infinity and nan bits) of a NV - * might be wider than just 16 bits. - * - * Below the NV_NAN logic has similar __PL_nan_u fallback, the only - * difference being the int32 constant being coerced. */ -# define __PL_inf_float_int32 0x7F800000 -static const union { unsigned int __i; float __f; } __PL_inf_u = - { __PL_inf_float_int32 }; -# define NV_INF ((NV)(__PL_inf_u.__f)) -# endif -#endif -#if !defined(NV_INF) -# define NV_INF ((NV)1.0/0.0) /* Some compilers will warn. */ -#endif - -#if !defined(NV_NAN) && defined(USE_LONG_DOUBLE) -# if !defined(NV_NAN) && defined(LDBL_NAN) -# define NV_NAN LDBL_NAN -# endif -# if !defined(NV_NAN) && defined(NANL) -# define NV_NAN NANL -# endif -# if !defined(NV_NAN) && defined(LDBL_QNAN) -# define NV_NAN LDBL_QNAN -# endif -#endif -#if !defined(NV_NAN) && defined(DBL_NAN) -# define NV_NAN (NV)DBL_NAN -#endif -#if !defined(NV_NAN) && defined(DBL_QNAN) -# define NV_NAN (NV)DBL_QNAN -#endif -#if !defined(NV_NAN) && defined(NAN) -# define NV_NAN (NV)NAN -#endif -#if !defined(NV_NAN) && defined(QNAN) -# define NV_NAN (NV)QNAN -#endif -#if !defined(NV_NAN) && defined(USE_LONG_DOUBLE) && defined(I_SUNMATH) -# define NV_NAN (NV)quiet_nan() -#endif -#if !defined(NV_NAN) -# if INTSIZE == 4 -/* See the discussion near __PL_inf_u. */ -# define __PL_nan_float_int32 0x7FC00000 -static const union { unsigned int __i; float __f; } __PL_nan_u = - { __PL_nan_float_int32 }; -# define NV_NAN ((NV)(__PL_nan_u.__f)) -# endif -#endif -#if !defined(NV_NAN) -# define NV_NAN ((NV)0.0/0.0) /* Some compilers will warn. */ -#endif -/* Do NOT try doing NV_NAN based on NV_INF and trying (NV_INF-NV_INF). - * Though IEEE-754-logically correct, some compilers (like Visual C 2003) - * falsely misoptimize that to zero (x-x is zero, right?) */ - #ifndef __cplusplus # if !defined(WIN32) && !defined(VMS) #ifndef crypt @@ -5619,6 +5525,124 @@ EXTCONST bool PL_valid_types_NV_set[]; #endif +/* In C99 we could use designated (named field) union initializers. + * In C89 we need to initialize the member declared first. + * + * With the U8_NV version you will want to have inner braces, + * while with the NV_U8 use just the NV.*/ +#define INFNAN_U8_NV_DECL EXTCONST union { U8 u8[NVSIZE]; NV nv; } +#define INFNAN_NV_U8_DECL EXTCONST union { NV nv; U8 u8[NVSIZE]; } + +#ifdef DOINIT + +/* PL_inf and PL_nan initialization. + * + * For inf and nan initialization the ultimate fallback is dividing + * one or zero by zero: however, some compilers will warn or even fail + * on divide-by-zero, but hopefully something earlier will work. + * + * If you are thinking of using HUGE_VAL for infinity, or using + * <math.h> functions to generate NV_INF (e.g. exp(1e9), log(-1.0)), + * stop. Neither will work portably: HUGE_VAL can be just DBL_MAX, + * and the math functions might be just generating DBL_MAX, or even zero. + * + * Also, do NOT try doing NV_NAN based on NV_INF and trying (NV_INF-NV_INF). + * Though logically correct, some compilers (like Visual C 2003) + * falsely misoptimize that to zero (x-x is always zero, right?) + */ + +# ifdef USE_QUADMATH +/* Cannot use HUGE_VALQ for PL_inf because not a compile-time + * constant. Also, the quadmath literals are anon structs which + * -Wc++-compat doesn't like. */ +GCC_DIAG_IGNORE(-Wc++-compat); +INFNAN_NV_U8_DECL PL_inf = { 1.0Q/0.0Q }; +GCC_DIAG_RESTORE; +# elif NVSIZE == LONG_DOUBLESIZE && defined(LONGDBLINFBYTES) +INFNAN_U8_NV_DECL PL_inf = { { LONGDBLINFBYTES } }; +# elif NVSIZE == DOUBLESIZE && defined(DOUBLEINFBYTES) +INFNAN_U8_NV_DECL PL_inf = { { DOUBLEINFBYTES } }; +# else +# if NVSIZE == LONG_DOUBLESIZE && defined(USE_LONG_DOUBLE) +# if defined(LDBL_INFINITY) +INFNAN_NV_U8_DECL PL_inf = { LDBL_INFINITY }; +# elif defined(LDBL_INF) +INFNAN_NV_U8_DECL PL_inf = { LDBL_INF }; +# elif defined(INFINITY) +INFNAN_NV_U8_DECL PL_inf = { (NV)INFINITY }; +# elif defined(INF) +INFNAN_NV_U8_DECL PL_inf = { (NV)INF }; +# else +INFNAN_NV_U8_DECL PL_inf = { 1.0L/0.0L }; /* keep last */ +# endif +# else +# if defined(DBL_INFINITY) +INFNAN_NV_U8_DECL PL_inf = { DBL_INFINITY }; +# elif defined(DBL_INF) +INFNAN_NV_U8_DECL PL_inf = { DBL_INF }; +# elif defined(INFINITY) /* C99 */ +INFNAN_NV_U8_DECL PL_inf = { (NV)INFINITY }; +# elif defined(INF) +INFNAN_NV_U8_DECL PL_inf = { (NV)INF }; +# else +INFNAN_NV_U8_DECL PL_inf = { 1.0/0.0 }; /* keep last */ +# endif +# endif +# endif + +# ifdef USE_QUADMATH +/* Cannot use nanq("0") for PL_nan because not a compile-time + * constant. Also, the quadmath literals are anon structs which + * -Wc++-compat doesn't like. */ +GCC_DIAG_IGNORE(-Wc++-compat); +INFNAN_NV_U8_DECL PL_nan = { 0.0Q/0.0Q }; +GCC_DIAG_RESTORE; +# elif NVSIZE == LONG_DOUBLESIZE && defined(LONGDBLNANBYTES) +INFNAN_U8_NV_DECL PL_nan = { { LONGDBLNANBYTES } }; +# elif NVSIZE == DOUBLESIZE && defined(DOUBLENANBYTES) +INFNAN_U8_NV_DECL PL_nan = { { DOUBLENANBYTES } }; +# else +# if NVSIZE == LONG_DOUBLESIZE && defined(USE_LONG_DOUBLE) +# if defined(LDBL_NAN) +INFNAN_NV_U8_DECL PL_nan = { LDBL_NAN }; +# elif defined(LDBL_QNAN) +INFNAN_NV_U8_DECL PL_nan = { LDBL_QNAN }; +# elif defined(NAN) +INFNAN_NV_U8_DECL PL_nan = { (NV)NAN }; +# else +INFNAN_NV_U8_DECL PL_nan = { 0.0L/0.0L }; /* keep last */ +# endif +# else +# if defined(DBL_NAN) +INFNAN_NV_U8_DECL PL_nan = { DBL_NAN }; +# elif defined(DBL_QNAN) +INFNAN_NV_U8_DECL PL_nan = { DBL_QNAN }; +# elif defined(NAN) /* C99 */ +INFNAN_NV_U8_DECL PL_nan = { (NV)NAN }; +# else +INFNAN_NV_U8_DECL PL_nan = { 0.0/0.0 }; /* keep last */ +# endif +# endif +# endif + +#else + +INFNAN_NV_U8_DECL PL_inf; +INFNAN_NV_U8_DECL PL_nan; + +#endif + +/* If you have not defined NV_INF/NV_NAN (like for example win32/win32.h), + * we will define NV_INF/NV_NAN as the nv part of the global const + * PL_inf/PL_nan. Note, however, that the preexisting NV_INF/NV_NAN + * might not be a compile-time constant, in which case it cannot be + * used to initialize PL_inf/PL_nan above. */ +#ifndef NV_INF +# define NV_INF PL_inf.nv +#endif +#ifndef NV_NAN +# define NV_NAN PL_nan.nv +#endif /* if these never got defined, they need defaults */ #ifndef PERL_SET_CONTEXT @@ -6579,7 +6603,15 @@ extern void moncontrol(int); #endif /* LONG_DOUBLEKIND */ -#if NVSIZE == DOUBLESIZE +#ifdef USE_QUADMATH /* assume quadmath endianness == native double endianness */ +# if defined(DOUBLE_LITTLE_ENDIAN) +# define NV_LITTLE_ENDIAN +# elif defined(DOUBLE_BIG_ENDIAN) +# define NV_BIG_ENDIAN +# elif defined(DOUBLE_MIX_ENDIAN) /* stretch */ +# define NV_MIX_ENDIAN +# endif +#elif NVSIZE == DOUBLESIZE # ifdef DOUBLE_LITTLE_ENDIAN # define NV_LITTLE_ENDIAN # endif @@ -6598,6 +6630,321 @@ extern void moncontrol(int); # endif #endif +/* NaNs (not-a-numbers) can carry payload bits, in addition to + * "nan-ness". Part of the payload is the quiet/signaling bit. + * To back up a bit (harhar): + * + * For IEEE 754 64-bit formats [1]: + * + * s 000 (mantissa all-zero) zero + * s 000 (mantissa non-zero) subnormals (denormals) + * s 001 ... 7fe normals + * s 7ff q nan + * + * For IEEE 754 128-bit formats: + * + * s 0000 (mantissa all-zero) zero + * s 0000 (mantissa non-zero) subnormals (denormals) + * s 0001 ... 7ffe normals + * s 7fff q nan + * + * [1] this looks like big-endian, but applies equally to little-endian. + * + * s = Sign bit. Yes, zeros and nans can have negative sign, + * the interpretation is application-specific. + * + * q = Quietness bit, the interpretation is platform-specific. + * Most platforms have the most significant bit being one + * meaning quiet, but some (older mips, hppa) have the msb + * being one meaning signaling. Note that the above means + * that on most platforms there cannot be signaling nan with + * zero payload because that is identical with infinity; + * while conversely on older mips/hppa there cannot be a quiet nan + * because that is identical with infinity. + * + * Moreover, whether there is any behavioral difference + * between quiet and signaling NaNs, depends on the platform. + * + * x86 80-bit extended precision is different, the mantissa bits: + * + * 63 62 61 30387+ pre-387 visual c + * -------- ---- -------- -------- + * 0 0 0 invalid infinity + * 0 0 1 invalid snan + * 0 1 0 invalid snan + * 0 1 1 invalid snan + * 1 0 0 infinity snan 1.#INF + * 1 0 1 snan 1.#SNAN + * 1 1 0 qnan -1.#IND (x86 chooses this to negative) + * 1 1 1 qnan 1.#QNAN + * + * This means that in this format there are 61 bits available + * for the nan payload. + * + * In all platforms, the payload bytes (and bits, some of them are + * often in a partial byte) themselves can be either all zero (x86), + * all one (sparc or mips), or a mixture: in IEEE 754 128-bit double + * or in a double-double, the first half of the payload can follow the + * native double, while in the second half the payload can be all + * zeros. (Therefore the mask for payload bits is not necessarily + * identical to bit complement of the NaN.) Another way of putting + * this: the payload for the default NaN might not be zero. + * + * For the x86 80-bit long doubles, the trailing bytes (the 80 bits + * being 'packaged' in either 12 or 16 bytes) can be whatever random + * garbage. + * + * Furthermore, the semantics of the sign bit on NaNs are platform-specific. + * On normal floats, the sign bit being on means negative. But this may, + * or may not, be reverted on NaNs: in other words, the default NaN might + * have the sign bit on, and therefore look like negative if you look + * at it at the bit level. + * + * NaN payloads are not propagated even on copies, or in arithmetics. + * They *might* be, according to some rules, on your particular + * cpu/os/compiler/libraries, but no guarantees. + * + * To summarize, on most platforms, and for 64-bit doubles + * (using big-endian ordering here): + * + * [7FF8000000000000..7FFFFFFFFFFFFFFF] quiet + * [FFF8000000000000..FFFFFFFFFFFFFFFF] quiet + * [7FF0000000000001..7FF7FFFFFFFFFFFF] signaling + * [FFF0000000000001..FFF7FFFFFFFFFFFF] signaling + * + * The C99 nan() is supposed to generate *quiet* NaNs. + * + * Note the asymmetry: + * The 7FF0000000000000 is positive infinity, + * the FFF0000000000000 is negative infinity. + */ + +/* NVMANTBITS is the number of _real_ mantissa bits in an NV. + * For the standard IEEE 754 fp this number is usually one less that + * *DBL_MANT_DIG because of the implicit (aka hidden) bit, which isn't + * real. For the 80-bit extended precision formats (x86*), the number + * of mantissa bits... depends. For normal floats, it's 64. But for + * the inf/nan, it's different (zero for inf, 61 for nan). + * NVMANTBITS works for normal floats. */ + +/* We do not want to include the quiet/signaling bit. */ +#define NV_NAN_BITS (NVMANTBITS - 1) + +#if defined(USE_LONG_DOUBLE) && NVSIZE > DOUBLESIZE +# if LONG_DOUBLEKIND == LONG_DOUBLE_IS_IEEE_754_128_BIT_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 13 +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_IEEE_754_128_BIT_BIG_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 2 +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 7 +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_BIG_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 2 +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 13 +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_BIG_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 1 +# else +# error "Unexpected long double format" +# endif +#else +# ifdef USE_QUADMATH +# ifdef NV_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 13 +# elif defined(NV_BIG_ENDIAN) +# define NV_NAN_QS_BYTE_OFFSET 2 +# else +# error "Unexpected quadmath format" +# endif +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_32_BIT_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 2 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_32_BIT_BIG_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 1 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 6 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_BIG_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 1 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_128_BIT_LITTLE_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 13 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_128_BIT_BIG_ENDIAN +# define NV_NAN_QS_BYTE_OFFSET 2 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_MIXED_ENDIAN_LE_BE +# define NV_NAN_QS_BYTE_OFFSET 2 /* bytes 4 5 6 7 0 1 2 3 (MSB 7) */ +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_MIXED_ENDIAN_BE_LE +# define NV_NAN_QS_BYTE_OFFSET 5 /* bytes 3 2 1 0 7 6 5 4 (MSB 7) */ +# else +# error "Unexpected double format" +# endif +#endif +/* NV_NAN_QS_BYTE is the byte to test for the quiet/signaling */ +#define NV_NAN_QS_BYTE(nvp) (((U8*)(nvp))[NV_NAN_QS_BYTE_OFFSET]) +/* NV_NAN_QS_BIT is the bit to test in the NV_NAN_QS_BYTE_OFFSET + * for the quiet/signaling */ +#if defined(USE_LONG_DOUBLE) && \ + (LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN || \ + LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_BIG_ENDIAN) +# define NV_NAN_QS_BIT_SHIFT 6 /* 0x40 */ +#elif defined(USE_LONG_DOUBLE) && \ + (LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_LITTLE_ENDIAN || \ + LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_BIG_ENDIAN) +# define NV_NAN_QS_BIT_SHIFT 3 /* 0x08, but not via NV_NAN_BITS */ +#else +# define NV_NAN_QS_BIT_SHIFT ((NV_NAN_BITS) % 8) /* usually 3, or 0x08 */ +#endif +#define NV_NAN_QS_BIT (1 << (NV_NAN_QS_BIT_SHIFT)) +/* NV_NAN_QS_BIT_OFFSET is the bit offset from the beginning of a NV + * (bytes ordered big-endianly) for the quiet/signaling bit + * for the quiet/signaling */ +#define NV_NAN_QS_BIT_OFFSET \ + (8 * (NV_NAN_QS_BYTE_OFFSET) + (NV_NAN_QS_BIT_SHIFT)) +/* NV_NAN_QS_QUIET (always defined) is one if the NV_NAN_QS_QS_BIT being + * on/one indicates quiet NaN. NV_NAN_QS_SIGNALING (also always defined) + * is on/one if the NV_NAN_QS_BIT being one indicates signaling NaN. */ +#define NV_NAN_QS_QUIET \ + ((NV_NAN_QS_BYTE(PL_nan.u8) & NV_NAN_QS_BIT) == NV_NAN_QS_BIT) +#define NV_NAN_QS_SIGNALING (!(NV_NAN_QS_QUIET)) +#define NV_NAN_QS_TEST(nvp) (NV_NAN_QS_BYTE(nvp) & NV_NAN_QS_BIT) +/* NV_NAN_IS_QUIET() returns true if the NV behind nvp is a NaN, + * whether it is a quiet NaN, NV_NAN_IS_SIGNALING() if a signaling NaN. + * Note however that these do not check whether the nvp is a NaN. */ +#define NV_NAN_IS_QUIET(nvp) \ + (NV_NAN_QS_TEST(nvp) == (NV_NAN_QS_QUIET ? NV_NAN_QS_BIT : 0)) +#define NV_NAN_IS_SIGNALING(nvp) \ + (NV_NAN_QS_TEST(nvp) == (NV_NAN_QS_QUIET ? 0 : NV_NAN_QS_BIT)) +#define NV_NAN_SET_QUIET(nvp) \ + (NV_NAN_QS_QUIET ? \ + (NV_NAN_QS_BYTE(nvp) |= NV_NAN_QS_BIT) : \ + (NV_NAN_QS_BYTE(nvp) &= ~NV_NAN_QS_BIT)) +#define NV_NAN_SET_SIGNALING(nvp) \ + (NV_NAN_QS_QUIET ? \ + (NV_NAN_QS_BYTE(nvp) &= ~NV_NAN_QS_BIT) : \ + (NV_NAN_QS_BYTE(nvp) |= NV_NAN_QS_BIT)) +#define NV_NAN_QS_XOR(nvp) (NV_NAN_QS_BYTE(nvp) ^= NV_NAN_QS_BIT) + +/* NV_NAN_PAYLOAD_MASK: masking the nan payload bits. + * + * NV_NAN_PAYLOAD_PERM: permuting the nan payload bytes. + * 0xFF means "don't go here".*/ + +/* Shorthands to avoid typoses. */ +#define NV_NAN_PAYLOAD_PERM_0_TO_7 \ + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 +#define NV_NAN_PAYLOAD_PERM_7_TO_0 \ + 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0 +#define NV_NAN_PAYLOAD_MASK_IEEE_754_128_LE \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00 +#define NV_NAN_PAYLOAD_PERM_IEEE_754_128_LE \ + NV_NAN_PAYLOAD_PERM_0_TO_7, \ + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xFF, 0xFF +#define NV_NAN_PAYLOAD_MASK_IEEE_754_128_BE \ + 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +#define NV_NAN_PAYLOAD_PERM_IEEE_754_128_BE \ + 0xFF, 0xFF, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, \ + NV_NAN_PAYLOAD_PERM_7_TO_0 +#define NV_NAN_PAYLOAD_MASK_IEEE_754_64_LE \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00 +#define NV_NAN_PAYLOAD_PERM_IEEE_754_64_LE \ + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xFF +#define NV_NAN_PAYLOAD_MASK_IEEE_754_64_BE \ + 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +#define NV_NAN_PAYLOAD_PERM_IEEE_754_64_BE \ + 0xFF, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0 + +#if defined(USE_LONG_DOUBLE) && NVSIZE > DOUBLESIZE +# if LONG_DOUBLEKIND == LONG_DOUBLE_IS_IEEE_754_128_BIT_LITTLE_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_128_LE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_128_LE +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_IEEE_754_128_BIT_BIG_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_128_BE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_128_BE +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_LITTLE_ENDIAN +# if LONG_DOUBLESIZE == 12 +# define NV_NAN_PAYLOAD_MASK \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, \ + 0x00, 0x00, 0x00, 0x00 +# define NV_NAN_PAYLOAD_PERM \ + NV_NAN_PAYLOAD_PERM_0_TO_7, 0xFF, 0xFF, 0xFF, 0xFF +# elif LONG_DOUBLESIZE == 16 +# define NV_NAN_PAYLOAD_MASK \ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +# define NV_NAN_PAYLOAD_PERM \ + NV_NAN_PAYLOAD_PERM_0_TO_7, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +# else +# error "Unexpected x86 80-bit little-endian long double format" +# endif +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_X86_80_BIT_BIG_ENDIAN +# if LONG_DOUBLESIZE == 12 +# define NV_NAN_PAYLOAD_MASK \ + 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x00, 0x00 +# define NV_NAN_PAYLOAD_PERM \ + NV_NAN_PAYLOAD_PERM_7_TO_0, 0xFF, 0xFF, 0xFF, 0xFF +# elif LONG_DOUBLESIZE == 16 +# define NV_NAN_PAYLOAD_MASK \ + 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, \ + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +# define NV_NAN_PAYLOAD_PERM \ + NV_NAN_PAYLOAD_PERM_7_TO_0, \ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +# else +# error "Unexpected x86 80-bit little-endian long double format" +# endif +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_LITTLE_ENDIAN +/* For double-double we assume only the first double is used for NaN. */ +# define NV_NAN_PAYLOAD_MASK \ + NV_NAN_PAYLOAD_MASK_IEEE_754_64_LE +# define NV_NAN_PAYLOAD_PERM \ + NV_NAN_PAYLOAD_PERM_IEEE_754_64_LE +# elif LONG_DOUBLEKIND == LONG_DOUBLE_IS_DOUBLEDOUBLE_128_BIT_BIG_ENDIAN +# define NV_NAN_PAYLOAD_MASK \ + NV_NAN_PAYLOAD_MASK_IEEE_754_64_BE +# define NV_NAN_PAYLOAD_PERM \ + NV_NAN_PAYLOAD_PERM_IEEE_754_64_BE +# else +# error "Unexpected long double format" +# endif +#else +# ifdef USE_QUADMATH /* quadmath is not long double */ +# ifdef NV_LITTLE_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_128_LE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_128_LE +# elif defined(NV_BIG_ENDIAN) +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_128_BE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_128_BE +# else +# error "Unexpected quadmath format" +# endif +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_32_BIT_LITTLE_ENDIAN +# define NV_NAN_PAYLOAD_MASK 0xff, 0xff, 0x07, 0x00 +# define NV_NAN_PAYLOAD_PERM 0x0, 0x1, 0x2, 0xFF +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_32_BIT_BIG_ENDIAN +# define NV_NAN_PAYLOAD_MASK 0x00, 0x07, 0xff, 0xff +# define NV_NAN_PAYLOAD_PERM 0xFF, 0x2, 0x1, 0x0 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_LITTLE_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_64_LE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_64_LE +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_BIG_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_64_BE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_64_BE +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_128_BIT_LITTLE_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_128_LE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_128_LE +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_128_BIT_BIG_ENDIAN +# define NV_NAN_PAYLOAD_MASK NV_NAN_PAYLOAD_MASK_IEEE_754_128_BE +# define NV_NAN_PAYLOAD_PERM NV_NAN_PAYLOAD_PERM_IEEE_754_128_BE +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_MIXED_ENDIAN_LE_BE +# define NV_NAN_PAYLOAD_MASK 0xff, 0xff, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff +# define NV_NAN_PAYLOAD_PERM 0x4, 0x5, 0x6, 0xFF, 0x0, 0x1, 0x2, 0x3 +# elif DOUBLEKIND == DOUBLE_IS_IEEE_754_64_BIT_MIXED_ENDIAN_BE_LE +# define NV_NAN_PAYLOAD_MASK 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff +# define NV_NAN_PAYLOAD_PERM 0x3, 0x2, 0x1, 0x0, 0xFF, 0x6, 0x5, 0x4 +# else +# error "Unexpected double format" +# endif +#endif /* (KEEP THIS LAST IN perl.h!) diff --git a/plan9/config_sh.sample b/plan9/config_sh.sample index 2330ef5..7fd970d 100644 --- a/plan9/config_sh.sample +++ b/plan9/config_sh.sample @@ -611,7 +611,10 @@ db_version_patch='' direntrytype='struct dirent' dlext='none' dlsrc='dl_none.xs' +doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' doublekind='3' +doublemantbits='52' +doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' doublesize='8' drand01='(rand() / (double) ((unsigned long)1 << 15))' drand48_r_proto='0' @@ -835,7 +838,10 @@ lns='/bin/ln -s' localtime_r_proto='0' locincpth='' loclibpth='' +longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblkind='0' +longdblmantbits='64' +longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblsize='8' longlongsize='8' longsize='4' @@ -888,6 +894,7 @@ nv_preserves_uv_bits='31' nveformat='"e"' nvfformat='"f"' nvgformat='"g"' +nvmantbits='52' nvsize='8' nvtype='double' o_nonblock='O_NONBLOCK' diff --git a/symbian/config.sh b/symbian/config.sh index a114f06..a5aa477 100644 --- a/symbian/config.sh +++ b/symbian/config.sh @@ -558,7 +558,10 @@ db_version_patch='0' direntrytype='struct dirent' dlext='dll' dlsrc='dl_symbian.xs' +doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' doublekind='4' +doublemantbits='52' +doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' doublesize='8' drand01="((rand() & 0x7FFF) / (double) ((unsigned long)1 << 15))" drand48_r_proto='0' @@ -730,7 +733,10 @@ libc='stdlib' libm_lib_version='0' libperl='libperl.a' localtime_r_proto='0' +longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblkind=0 +longdblmantbits='64' +longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblsize=8 longlongsize=8 longsize='4' @@ -757,6 +763,7 @@ nv_preserves_uv_bits='0' nveformat='"e"' nvfformat='"f"' nvgformat='"g"' +nvmantbits='52' nvsize='8' nvtype='double' o_nonblock='O_NONBLOCK' diff --git a/uconfig.h b/uconfig.h index eb6a5b9..ce693a0 100644 --- a/uconfig.h +++ b/uconfig.h @@ -4802,6 +4802,53 @@ /*#define PERL_PRIeldbl "lle" / **/ /*#define PERL_SCNfldbl "llf" / **/ +/* DOUBLEINFBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes for the double precision infinity. + */ +/* DOUBLENANBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes (0xHH) for the double precision not-a-number. + */ +/* LONGDBLINFBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes for the long double precision infinity. + */ +/* LONGDBLNANBYTES: + * This symbol, if defined, is a comma-separated list of + * hexadecimal bytes (0xHH) for the long double precision not-a-number. + */ +#define DOUBLEINFBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f /**/ +#define DOUBLENANBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f /**/ +#define LONGDBLINFBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /**/ +#define LONGDBLNANBYTES 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /**/ + +/* DOUBLEMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * there are in double precision floating point format. + * Note that this is usually DBL_MANT_DIG minus one, since + * with the standard IEEE 754 formats DBL_MANT_DIG includes + * the implicit bit, which doesn't really exist. + */ +#define DOUBLEMANTBITS 52 + +/* LONGDBLMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * there are in long double precision floating point format. + * Note that this can be LDBL_MANT_DIG minus one, + * since LDBL_MANT_DIG can include the IEEE 754 implicit bit. + * The common x86-style 80-bit long double does not have + * an implicit bit. + */ +#define LONGDBLMANTBITS 64 + +/* NVMANTBITS: + * This symbol, if defined, tells how many mantissa bits + * (not including implicit bit) there are in a Perl NV. + * This depends on which floating point type was chosen. + */ +#define NVMANTBITS 52 /**/ + /* NEED_VA_COPY: * This symbol, if defined, indicates that the system stores * the variable argument list datatype, va_list, in a format @@ -5167,6 +5214,6 @@ #endif /* Generated from: - * 496e563499c7b715275d61ae663d25dd20d963c75f9d3ee7850dae949df14136 config_h.SH - * 49c2c25e94c0a8057a87bf294e1dd9bdadaeb72e47c22362e7699344dd9fd7d3 uconfig.sh + * c784534c0c9ca4f445c518a18404c8fd0b3be9aac3de1ee4a94453807935584c config_h.SH + * 0ce9d24f6ed83c533882929bc7c0138fe345656c4b7070aad99bb103dbf3790a uconfig.sh * ex: set ro: */ diff --git a/uconfig.sh b/uconfig.sh index b54b0c6..bd889e3 100644 --- a/uconfig.sh +++ b/uconfig.sh @@ -547,7 +547,10 @@ db_version_major='0' db_version_minor='0' db_version_patch='0' direntrytype='struct dirent' +doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f' doublekind='3' +doublemantbits='52' +doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f' doublesize='8' drand01="Perl_drand48()" drand48_r_proto='0' @@ -706,7 +709,10 @@ ivtype='long' ld_can_script='define' lib_ext='.a' localtime_r_proto='0' +longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblkind=0 +longdblmantbits='64' +longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00' longdblsize=8 longlongsize=8 longsize='4' @@ -731,6 +737,7 @@ nv_preserves_uv_bits='0' nveformat='"e"' nvfformat='"f"' nvgformat='"g"' +nvmantbits='52' nvsize='8' nvtype='double' o_nonblock='O_NONBLOCK' diff --git a/uconfig64.sh b/uconfig64.sh index a297ae5..ec09c1e 100644 --- a/uconfig64.sh +++ b/uconfig64.sh @@ -548,7 +548,10 @@ db_version_major='0' db_version_minor='0' db_version_patch='0' **** PATCH TRUNCATED AT 2000 LINES -- 282 NOT SHOWN **** -- Perl5 Master Repository
