diff options
author | Jarkko Hietaniemi <jhi@iki.fi> | 2016-08-14 22:52:40 -0400 |
---|---|---|
committer | Steve Hay <steve.m.hay@googlemail.com> | 2017-08-09 13:24:27 +0100 |
commit | 20df966d7ace0fe3e66dc966fd8e5024940ee11d (patch) | |
tree | 603933e8e165a00a6b1a90606e34512ebfed45ad /sv.c | |
parent | 865f60cb2a1a372f004ba8a8b99fa3d61afc090d (diff) | |
download | perl-20df966d7ace0fe3e66dc966fd8e5024940ee11d.tar.gz |
Handle subnormals of x86 80-bit
(cherry picked from commit f40ac91c3b9891b83f3d253861009c290584b646)
Diffstat (limited to 'sv.c')
-rw-r--r-- | sv.c | 44 |
1 files changed, 30 insertions, 14 deletions
@@ -10986,8 +10986,8 @@ Perl_sv_vcatpvfn(pTHX_ SV *const sv, const char *const pat, const STRLEN patlen, * are being extracted from (either directly from the long double in-memory * presentation, or from the uquad computed via frexp+ldexp). frexp also * is used to update the exponent. The subnormal is set to true - * for IEEE 754 subnormals/denormals. The vhex is the pointer to - * the beginning of the output buffer (of VHEX_SIZE). + * for IEEE 754 subnormals/denormals (including the x86 80-bit format). + * The vhex is the pointer to the beginning of the output buffer of VHEX_SIZE. * * The tricky part is that S_hextract() needs to be called twice: * the first time with vend as NULL, and the second time with vend as @@ -12450,15 +12450,25 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p #if NVSIZE > DOUBLESIZE # ifdef HEXTRACT_HAS_IMPLICIT_BIT /* In this case there is an implicit bit, - * and therefore the exponent is shifted by one, - * unless this is a subnormal/denormal. */ - if (!subnormal) { - exponent--; - } + * and therefore the exponent is shifted by one. */ + exponent--; # else - /* In this case there is no implicit bit, - * and the exponent is shifted by the first xdigit. */ - exponent -= 4; +# ifdef NV_X86_80_BIT + if (subnormal) { + /* The subnormals of the x86-80 have a base exponent of -16382, + * (while the physical exponent bits are zero) but the frexp() + * returned the scientific-style floating exponent. We want + * to map the last one as: + * -16831..-16384 -> -16382 (the last normal is 0x1p-16382) + * -16835..-16388 -> -16384 + * since we want to keep the first hexdigit + * as one of the [8421]. */ + exponent = -4 * ( (exponent + 1) / -4) - 2; + } else { + exponent -= 4; + } +# endif + /* TBD: other non-implicit-bit platforms than the x86-80. */ # endif #endif @@ -12499,10 +12509,15 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p #endif if (subnormal) { +#ifndef NV_X86_80_BIT if (vfnz[0] > 1) { - /* We need to right shift the hex nybbles so - * that the output of the subnormal starts - * from the first true bit. */ + /* IEEE 754 subnormals (but not the x86 80-bit): + * we want "normalize" the subnormal, + * so we need to right shift the hex nybbles + * so that the output of the subnormal starts + * from the first true bit. (Another, equally + * valid, policy would be to dump the subnormal + * nybbles as-is, to display the "physical" layout.) */ int i, n; U8 *vshr; /* Find the ceil(log2(v[0])) of @@ -12518,6 +12533,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p vlnz++; } } +#endif v0 = vfnz; } else { v0 = vhex; @@ -12566,7 +12582,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p /* If the overflow goes all the * way to the front, we need to * insert 0x1 in front, and adjust - * the argument. */ + * the exponent. */ Move(v0, v0 + 1, vn, char); *v0 = 0x1; exponent += 4; |