Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MinGW.org builds - infnan and pack test failures due to LD handling #15453

Open
p5pRT opened this issue Jul 17, 2016 · 15 comments
Open

MinGW.org builds - infnan and pack test failures due to LD handling #15453

p5pRT opened this issue Jul 17, 2016 · 15 comments
Labels

Comments

@p5pRT
Copy link

p5pRT commented Jul 17, 2016

Migrated from rt.perl.org#128643 (status was 'open')

Searchable as RT128643$

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @dcollinsn

Hello,

I have built perl using long doubles with the following Win32 tools​:

W​:\buildbot\windows1\win32-mingw-ld\build>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c​:/mingw/bin/../libexec/gcc/mingw32/4.9.3/lto-wrapper.exe
Target​: mingw32
Configured with​: ../src/gcc-4.9.3/configure --build=x86_64-pc-linux-gnu --host=mingw32 --prefix=/mingw --disable-win32-registry --target=mingw32 --with-arch=i586 --enable-languages=c,c++,objc,obj-c++,fortran,ada --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libstdcxx-debug --with-tune=generic --enable-nls
Thread model​: win32
gcc version 4.9.3 (GCC)

W​:\buildbot\windows1\win32-mingw-ld\build>perl.exe -Ilib -V
Summary of my perl5 (revision 5 version 25 subversion 3) configuration​:

  Platform​:
  osname=MSWin32
  osvers=10.0
  archname=MSWin32-x86-multi-thread-ld
  uname=''
  config_args='undef'
  hint=recommended
  useposix=true
  d_sigaction=undef
  useithreads=define
  usemultiplicity=define
  use64bitint=undef
  use64bitall=undef
  uselongdouble=define
  usemymalloc=n
  bincompat5005=undef
  Compiler​:
  cc='gcc'
  ccflags =' -s -O2 -DWIN32 -DPERL_TEXTMODE_SCRIPTS -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -D__USE_MINGW_ANSI_STDIO -fwrapv -fno-strict-aliasing -mms-bitfields'
  optimize='-s -O2'
  cppflags='-DWIN32'
  ccversion=''
  gccversion='4.9.3'
  gccosandvers=''
  intsize=4
  longsize=4
  ptrsize=4
  doublesize=8
  byteorder=1234
  doublekind=3
  d_longlong=define
  longlongsize=8
  d_longdbl=define
  longdblsize=12
  longdblkind=3
  ivtype='long'
  ivsize=4
  nvtype='long double'
  nvsize=12
  Off_t='long long'
  lseeksize=8
  alignbytes=8
  prototype=define
  Linker and Libraries​:
  ld='g++'
  ldflags ='-s -L"c​:\perl\lib\CORE" -L"C​:\MinGW\lib"'
  libpth=C​:\MinGW\lib
  libs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
  perllibs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
  libc=
  so=dll
  useshrplib=true
  libperl=libperl525.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_win32.xs
  dlext=dll
  d_dlsymun=undef
  ccdlflags=' '
  cccdlflags=' '
  lddlflags='-mdll -s -L"c​:\perl\lib\CORE" -L"C​:\MinGW\lib"'

Characteristics of this binary (from libperl)​:
  Compile-time options​:
  HAS_TIMES
  HAVE_INTERP_INTERN
  MULTIPLICITY
  PERLIO_LAYERS
  PERL_COPY_ON_WRITE
  PERL_DONT_CREATE_GVSV
  PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
  PERL_IMPLICIT_CONTEXT
  PERL_IMPLICIT_SYS
  PERL_MALLOC_WRAP
  PERL_OP_PARENT
  PERL_PRESERVE_IVUV
  USE_ITHREADS
  USE_LARGE_FILES
  USE_LOCALE
  USE_LOCALE_COLLATE
  USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC
  USE_LOCALE_TIME
  USE_LONG_DOUBLE
  USE_PERLIO
  USE_PERL_ATOF
  Built under MSWin32
  Compiled at Jul 16 2016 20​:39​:38
  @​INC​:
  lib
  W​:/buildbot/windows1/win32-mingw-ld/build/lib
  .

I have test failures​:

# Failed test 310 - 9**9**9 is Inf at op/infnan.t line 249
# got "1.18973149535723177e+4932"
# expected "Inf"
# Failed test 490 - sin(9**9**9) is NaN at op/infnan.t line 400
# got "0.866408717194837384"
# expected "NaN"
op/infnan.t ........................................................
Failed 2/658 subtests

<SNIP>

op/pack.t ..........................................................
Failed 2/14712 subtests
  (less 269 skipped subtests​: 14441 okay)
# Failed test 13177 - at op/pack.t line 1420
# got "173 1.28347651700000004e-045 42 215 173 1.28347651700000004e-045 42 215"
# expected "173 1.283476517e-045 42 215 173 1.283476517e-045 42 215"
# Failed test 13180 - at op/pack.t line 1433
# got "173 1.28347651700000004e-045 42 215"
# expected "173 1.283476517e-045 42 215"

The first part is caused by long doubles​:

W​:\buildbot\windows1\win32-mingw-ld\build>..\..\win32-mingw\build\perl.exe -le "print 9**9**9"
Inf
W​:\buildbot\windows1\win32-mingw-ld\build>perl.exe -le "print 9**9**9"
1.18973149535723177e+4932

The second part is probably your typical rounding error?

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @sisyphus

-----Original Message-----
From​: Dan Collins (via RT)
Sent​: Sunday, July 17, 2016 11​:18 AM
To​: bugs-bitbucket@​rt.perl.org
Subject​: [perl #128643] MinGW.org builds - infnan and pack test failures due
to LD handling

# New Ticket Created by Dan Collins
# Please include the string​: [perl #128643]
# in the subject line of all future correspondence about this issue.
# <URL​: https://rt-archive.perl.org/perl5/Ticket/Display.html?id=128643 >

Hello,

I have built perl using long doubles with the following Win32 tools​:

W​:\buildbot\windows1\win32-mingw-ld\build>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c​:/mingw/bin/../libexec/gcc/mingw32/4.9.3/lto-wrapper.exe
Target​: mingw32
Configured with​:
../src/gcc-4.9.3/configure --build=x86_64-pc-linux-gnu --host=mingw32 --prefix=/mingw
--disable-win32-registry --target=mingw32 --with-arch=i586 --enable-languages=c,c++,objc,obj-c++,fortran,ada
--enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions
--enable-version-specific-runtime-libs --enable-libstdcxx-debug --with-tune=generic
--enable-nls
Thread model​: win32
gcc version 4.9.3 (GCC)

[snip]

I have test failures​:

# Failed test 310 - 9**9**9 is Inf at op/infnan.t line 249
# got "1.18973149535723177e+4932"
# expected "Inf"
# Failed test 490 - sin(9**9**9) is NaN at op/infnan.t line 400
# got "0.866408717194837384"
# expected "NaN"
op/infnan.t ........................................................
Failed 2/658 subtests
<SNIP>
op/pack.t ..........................................................
Failed 2/14712 subtests
(less 269 skipped subtests​: 14441 okay)
# Failed test 13177 - at op/pack.t line 1420
# got "173 1.28347651700000004e-045 42 215 173
1.28347651700000004e-045 42 215"
# expected "173 1.283476517e-045 42 215 173 1.283476517e-045 42 215"
# Failed test 13180 - at op/pack.t line 1433
# got "173 1.28347651700000004e-045 42 215"
# expected "173 1.283476517e-045 42 215"

The first part is caused by long doubles​:

W​:\buildbot\windows1\win32-mingw-ld\build>..\..\win32-mingw\build\perl.exe
-le "print 9**9**9"
Inf
W​:\buildbot\windows1\win32-mingw-ld\build>perl.exe -le "print 9**9**9"
1.18973149535723177e+4932

Well .... (9**9)**9 is not Inf, but it's not 1.18973149535723177e+4932
either. It's 1.96627050475552913619e77, though perl prints it out as
1.96627050475552914e+077
However, all of my perl builds evaluate "9**9**9" as 9**(9**9) - which is
Inf even on __float128 perls.

I think this must be a bug with the specific compiler/runtime that you've
used.
I certainly can't reproduce the behaviour on any of my long double mingw
builds. (I haven't used the same compiler/runtime as you.)

If, in infnan.t, you replace the occurrences of 9**9**9 with 9**(9**9), does
that allow the tests to pass ?

The second part is probably your typical rounding error?

Dunno - those failures have been a fixture of all 'long double' mingw builds
since the 'long double' capability was added (in perl-5.21.something).

Cheers,
Rob

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From zefram@fysh.org

Dan Collins wrote​:

W​:\buildbot\windows1\win32-mingw-ld\build>perl.exe -le "print 9**9**9"
1.18973149535723177e+4932

That's the maximum representable finite value in this floating point
format. One would expect 9**9**9 to overflow to infinity; something's
screwy about the way overflow is being handled. Maybe something's
selecting an abnormal rounding mode. Or maybe the value is actually +Inf
but the output library doesn't know about that special case and parses
it as finite. Some of the other bugs you've seen involved missing zero
padding on textual output of numbers, so I suspect that the printf()
on this platform is only half written.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @dcollinsn

The binary representation of this number is​:

ff.ff.ff.ff.ff.ff.ff.ff.fe.7f

which is the largest possible extended precision value, and is not inf.
0+Inf does print as Inf on this "platform", and is represented as​:

0.0.0.0.0.0.0.80.ff.7f

Interestingly, 2*9**9**9 does properly give inf. So perhaps powl() is
broken on this platform.

perl -le "print (9**9**9)"
1.18973149535723177e+4932

perl -le "print (9**9**9)**2"
1.18973149535723177e+4932

perl -le "print (9**9**9)*2"
1.18973149535723177e+4932

perl -le "print 2*(9**9**9)"
Inf

Even with plain C​:

powl(9, powl(9, 9)) = 1.189731e+4932
powl(9, powl(9, powl(9, 9))) = inf
powl(powl(9, powl(9, 9)), 9) = inf
2*powl(9, powl(9, 9)) = inf

MinGW-w64 gets it right​:

powl(9, powl(9, 9)) = inf
powl(9, powl(9, powl(9, 9))) = inf
powl(powl(9, powl(9, 9)), 9) = inf
2*powl(9, powl(9, 9)) = inf

Perhaps worth a note in README.win32, otherwise just close?

On Sun, Jul 17, 2016 at 12​:14 AM, Zefram via RT <perlbug-followup@​perl.org>
wrote​:

Dan Collins wrote​:

W​:\buildbot\windows1\win32-mingw-ld\build>perl.exe -le "print 9**9**9"
1.18973149535723177e+4932

That's the maximum representable finite value in this floating point
format. One would expect 9**9**9 to overflow to infinity; something's
screwy about the way overflow is being handled. Maybe something's
selecting an abnormal rounding mode. Or maybe the value is actually +Inf
but the output library doesn't know about that special case and parses
it as finite. Some of the other bugs you've seen involved missing zero
padding on textual output of numbers, so I suspect that the printf()
on this platform is only half written.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From zefram@fysh.org

Dan Collins wrote​:

which is the largest possible extended precision value, and is not inf.

That's useful information.

perl -le "print (9**9**9)*2"
1.18973149535723177e+4932

Precedence problem. You should get into the habit of "-lwe"​:

$ perl -lwe 'print (9**9**9)*2'
print (...) interpreted as function at -e line 1.
Useless use of multiplication (*) in void context at -e line 1.
inf

perl -le "print 2*(9**9**9)"
Inf

I would strongly expect the multiplication to give the same result either
way round, even with powl() broken.

Even with plain C​:

powl(9, powl(9, 9)) = 1.189731e+4932
powl(9, powl(9, powl(9, 9))) = inf

That's weird. Failing to ever produce Inf would be understandable;
doing it in some cases but not others is very strange.

Perhaps worth a note in README.win32, otherwise just close?

Can we find a working powl()?

-zefram

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @dcollinsn

On Sat Jul 16 22​:31​:37 2016, zefram@​fysh.org wrote​:

Can we find a working powl()?

-zefram

I tried this experiment. I pulled the powl() out of mingw-w64, changed a few things to get it to interact with mingw.org without also needing to grab 20 different header files, and added it to win32.c/h. I obviously didn't do so correctly, because extensions aren't building properly​:

g++ POSIX.def -o ..\..\lib\auto\POSIX\POSIX.dll -mdll -s -L"c​:\perl\lib\CORE" -L"C​:\MinGW\lib" POSIX.o "..\..\lib\CORE\libperl525.a" -lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32 -Wl,--enable-auto-image-base
POSIX.o​:POSIX.c​:(.text+0x799e)​: undefined reference to `my_powl'
POSIX.o​:POSIX.c​:(.text+0x7ad0)​: undefined reference to `my_powl'
POSIX.o​:POSIX.c​:(.text+0x7c29)​: undefined reference to `my_powl'
collect2.exe​: error​: ld returned 1 exit status
dmake​: Error code 129, while making '..\..\lib\auto\POSIX\POSIX.dll'
Unsuccessful make(ext/POSIX)​: code=65280 at ..\make_ext.pl line 569.
dmake​: Error code 130, while making 'Extensions'

However, the generated miniperl seems to be cooperating​:

W​:\buildbot\windows1\win32ld\build>miniperl.exe -wle "print 9**9**9"
Inf

W​:\buildbot\windows1\win32ld\build>miniperl.exe -V
Can't locate Config.pm in @​INC (you may need to install the Config module) (@​INC contains​: .).
BEGIN failed--compilation aborted.

W​:\buildbot\windows1\win32ld\build>miniperl.exe -Ilib -V
Summary of my perl5 (revision 5 version 25 subversion 3) configuration​:

  Platform​:
  osname=MSWin32
  osvers=10.0
  archname=MSWin32-x86-multi-thread-ld
  uname=''
  config_args='undef'
  hint=recommended
  useposix=true
  d_sigaction=undef
  useithreads=define
  usemultiplicity=define
  use64bitint=undef
  use64bitall=undef
  uselongdouble=define
  usemymalloc=n
  bincompat5005=undef
  Compiler​:
  cc='gcc'
  ccflags =' -s -O2 -DWIN32 -DPERL_TEXTMODE_SCRIPTS -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -D__USE_MINGW_ANSI_STDIO -fwrapv -fno-strict-aliasing -mms-bitfields'
  optimize='-s -O2'
  cppflags='-DWIN32'
  ccversion=''
  gccversion='4.9.3'
  gccosandvers=''
  intsize=4
  longsize=4
  ptrsize=4
  doublesize=8
  byteorder=1234
  doublekind=3
  d_longlong=define
  longlongsize=8
  d_longdbl=define
  longdblsize=12
  longdblkind=3
  ivtype='long'
  ivsize=4
  nvtype='long double'
  nvsize=12
  Off_t='long long'
  lseeksize=8
  alignbytes=8
  prototype=define
  Linker and Libraries​:
  ld='g++'
  ldflags ='-s -L"c​:\perl\lib\CORE" -L"C​:\MinGW\lib"'
  libpth=C​:\MinGW\lib
  libs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
  perllibs=-lmoldname -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -lnetapi32 -luuid -lws2_32 -lmpr -lwinmm -lversion -lodbc32 -lodbccp32 -lcomctl32
  libc=
  so=dll
  useshrplib=true
  libperl=libperl525.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_win32.xs
  dlext=dll
  d_dlsymun=undef
  ccdlflags=' '
  cccdlflags=' '
  lddlflags='-mdll -s -L"c​:\perl\lib\CORE" -L"C​:\MinGW\lib"'

Characteristics of this binary (from libperl)​:
  Compile-time options​:
  HAS_TIMES
  HAVE_INTERP_INTERN
  PERLIO_LAYERS
  PERL_COPY_ON_WRITE
  PERL_DISABLE_PMC
  PERL_DONT_CREATE_GVSV
  PERL_EXTERNAL_GLOB
  PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
  PERL_IS_MINIPERL
  PERL_MALLOC_WRAP
  PERL_OP_PARENT
  PERL_PRESERVE_IVUV
  USE_LOCALE
  USE_LOCALE_COLLATE
  USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC
  USE_LOCALE_TIME
  USE_LONG_DOUBLE
  USE_NO_REGISTRY
  USE_PERLIO
  USE_PERL_ATOF
  USE_SITECUSTOMIZE
  Built under MSWin32
  Compiled at Jul 17 2016 12​:30​:05
  @​INC​:
  W​:\buildbot\windows1\win32ld\build\lib
  W​:\buildbot\windows1\win32ld\build\cpan\AutoLoader\lib
  W​:\buildbot\windows1\win32ld\build\dist\Carp\lib
  W​:\buildbot\windows1\win32ld\build\dist\PathTools
  W​:\buildbot\windows1\win32ld\build\dist\PathTools\lib
  W​:\buildbot\windows1\win32ld\build\cpan\ExtUtils-Install\lib
  W​:\buildbot\windows1\win32ld\build\cpan\ExtUtils-MakeMaker\lib
  W​:\buildbot\windows1\win32ld\build\cpan\ExtUtils-Manifest\lib
  W​:\buildbot\windows1\win32ld\build\cpan\File-Path\lib
  W​:\buildbot\windows1\win32ld\build\ext\re
  W​:\buildbot\windows1\win32ld\build\dist\Term-ReadLine\lib
  W​:\buildbot\windows1\win32ld\build\dist\Exporter\lib
  W​:\buildbot\windows1\win32ld\build\ext\File-Find\lib
  W​:\buildbot\windows1\win32ld\build\cpan\Text-Tabs\lib
  W​:\buildbot\windows1\win32ld\build\dist\constant\lib
  W​:\buildbot\windows1\win32ld\build\cpan\version\lib
  W​:\buildbot\windows1\win32ld\build\cpan\Text-ParseWords\lib
  W​:\buildbot\windows1\win32ld\build\dist\ExtUtils-ParseXS\lib
  W​:\buildbot\windows1\win32ld\build\cpan\Getopt-Long\lib
  W​:\buildbot\windows1\win32ld\build\cpan\parent\lib
  W​:\buildbot\windows1\win32ld\build\cpan\ExtUtils-Constant\lib
  .

(I'm also not entirely confident in the error handling in this patch, as I had to futz around with that a bit - the code I lifted used something called __mingw_raise_matherr, which doesn't seem to have an equivalent in mingw.org.)

dmake minitest reports an expected error in re/reg_mesg.t, a test in op/glob.t that I'm not sure about (Failed test 16 - ~ works at op/glob.t line 104), and still fails op/pack.t tests 13177 and 13180. The op/infnan.t errors are fixed.

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @dcollinsn

0001-RT-128643.patch
From 46fe0a3489d04c34dc7b150a2d0b5090476dc29c Mon Sep 17 00:00:00 2001
From: Dan Collins <dcollinsn@gmail.com>
Date: Sun, 17 Jul 2016 12:37:46 -0400
Subject: [PATCH] RT 128643

---
 win32/win32.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 win32/win32.h |   8 ++++
 2 files changed, 157 insertions(+)

diff --git a/win32/win32.c b/win32/win32.c
index 6ac73e2..408d455 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -4795,3 +4795,152 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
 }
 #  endif /* USE_ITHREADS */
 #endif /* HAVE_INTERP_INTERN */
+
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32__)
+/* NAN builtins for gcc, as they are not part of math.h  */
+#ifndef NANF
+#define NANF __builtin_nanf ("")
+#endif
+#ifndef NANL
+#define NANL __builtin_nanl ("")
+#endif
+
+
+#ifndef _SET_ERRNO
+#define _SET_ERRNO(x) errno = (x)
+#endif
+
+
+static long double
+internal_modf (long double value, long double *iptr)
+{
+  long double int_part = (long double) 0.0;
+#ifdef _WIN64
+  asm ("pushq %%rax\n\tsubq $8, %%rsp\n"
+    "fnstcw 4(%%rsp)\n"
+    "movzwl 4(%%rsp), %%eax\n"
+    "orb $12, %%ah\n"
+    "movw %%ax, (%%rsp)\n"
+    "fldcw (%%rsp)\n"
+    "frndint\n"
+    "fldcw 4(%%rsp)\n"
+    "addq $8, %%rsp\npopq %%rax" : "=t" (int_part) : "0" (value)); /* round */
+#else
+  asm ("push %%eax\n\tsubl $8, %%esp\n"
+    "fnstcw 4(%%esp)\n"
+    "movzwl 4(%%esp), %%eax\n"
+    "orb $12, %%ah\n"
+    "movw %%ax, (%%esp)\n"
+    "fldcw (%%esp)\n"
+    "frndint\n"
+    "fldcw 4(%%esp)\n"
+    "addl $8, %%esp\n\tpop %%eax\n" : "=t" (int_part) : "0" (value)); /* round */
+#endif
+  if (iptr)
+    *iptr = int_part;
+  return (isinf (value) ?  (long double) 0.0 : value - int_part);
+}
+
+long double __powil (long double x, int n);
+
+long double 
+my_powl (long double x, long double y)
+{
+  int x_class = fpclassify (x);
+  int y_class = fpclassify (y);
+  long odd_y = 0;
+  long double d, rslt;
+
+  if (y_class == FP_ZERO || x == 1.0L)
+    return 1.0L;
+  else if (x_class == FP_NAN || y_class == FP_NAN)
+    {
+      rslt = (signbit(x) ? -NANL : NANL);
+      _SET_ERRNO (EDOM);
+      return rslt;
+    }
+  else if (x_class == FP_ZERO)
+    {
+      if (y_class == FP_INFINITE)
+        return (signbit(y) ? HUGE_VALL : 0.0L);
+
+      if (signbit(x) && internal_modf (y, &d) != 0.0)
+        {
+          return signbit (y) ? (1.0 / -x) : 0.0L;
+        }
+      odd_y = (internal_modf (ldexpl (y, -1), &d) != 0.0) ? 1 : 0;
+      if (!signbit(y))
+        {
+          if (!odd_y || !signbit (x))
+            return 0.0L;
+          return -0.0L;
+        }
+
+      if (!odd_y || !signbit (x))
+        return HUGE_VALL;
+      return (signbit(x) ? -HUGE_VALL : HUGE_VALL);
+    }
+  else if (y_class == FP_INFINITE)
+    {
+      long double a_x;
+
+      if (x_class == FP_INFINITE)
+        return (signbit (y) ? 0.0L : HUGE_VALL);
+      a_x = (signbit (x) ? -x : x);
+      if (a_x == 1.0)
+        return 1.0L;
+      if (a_x > 1.0)
+        return (signbit (y) == 0 ? HUGE_VALL : 0.0L);
+      return (!signbit (y) ? 0.0L : HUGE_VALL);
+    }
+  else if (x_class == FP_INFINITE)
+    {
+      /* pow (x, y) signals the invalid operation exception for finite x < 0 and finite non-integer y.  */
+      if (signbit(x) && internal_modf (y, &d) != 0.0)
+        {
+          return signbit(y) ? 1.0 / -x : -x;
+        }
+      odd_y = (internal_modf (ldexpl (y, -1), &d) != 0.0) ? 1 : 0;
+      /* pow( -inf, y) = +0 for y<0 and not an odd integer,  */
+      if (signbit(x) && signbit(y) && !odd_y)
+        return 0.0L;
+      /* pow( -inf, y) = -inf for y an odd integer > 0.  */
+      if (signbit(x) && !signbit(y) && odd_y)
+        return -HUGE_VALL;
+      /* pow( -inf, y) = +inf for y>0 and not an odd integer.  */
+      if (signbit(x) && !signbit(y) && !odd_y)
+        return HUGE_VALL;
+      /* pow (+/-inf, y) is +/-0 with no exception for y an odd integer < 0. */
+      if (signbit(y))
+      {
+        /* pow (+/-inf, y) is +0 with no exception for finite y < 0 and not an odd integer.  */
+        return (odd_y && signbit(x) ? -0.0L : 0.0L);
+      }
+      /* pow (+/-inf, y) is +/-inf with no exception for finite y > 0 an odd integer.  */
+      /* pow (+/-inf, y) is +inf with no exception for finite y > 0 and not an odd integer.  */
+      return (odd_y && signbit(x) ? -HUGE_VALL : HUGE_VALL);
+    }
+
+  if (internal_modf (y, &d) != 0.0)
+    {
+      if (signbit (x))
+        {
+          _SET_ERRNO (EDOM);
+          return -NANL;
+        }
+      if (y == 0.5L)
+        {
+          asm ("fsqrt" : "=t" (rslt) : "0" (x));
+          return rslt;
+        }
+    }
+  else if ((d <= (long double) INT_MAX && d >= (long double) INT_MIN))
+     return __powil (x, (int) y);
+  /* As exp already checks for minlog and maxlog no further checks are necessary.  */
+  rslt = (long double) exp2l ((long double) y * log2l ((long double) fabsl (x)));
+
+  if (signbit (x) && internal_modf (ldexpl (y, -1), &d) != 0.0)
+    rslt = -rslt;
+  return rslt;
+}
+#endif
\ No newline at end of file
diff --git a/win32/win32.h b/win32/win32.h
index 9b79e00..d89baa4 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -662,5 +662,13 @@ DllExport void *win32_signal_context(void);
 #define Win_CreateSemaphore   CreateSemaphore
 #endif
 
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32__)
+/* MinGW.org provides a powl that is broken: 9**9**9 returns
+ * LDBL_MAX instead of INF.
+ */
+#define powl my_powl
+long double my_powl (long double x, long double y);
+#endif
+
 #endif /* _INC_WIN32_PERL5 */
 
-- 
2.8.3

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From zefram@fysh.org

Dan Collins via RT wrote​:

POSIX.o​:POSIX.c​:(.text+0x799e)​: undefined reference to `my_powl'

You need to add it to the core export list for the linker.

W​:\buildbot\windows1\win32ld\build>miniperl.exe -wle "print 9**9**9"
Inf

W00t.

+ asm ("pushq %%rax\n\tsubq $8, %%rsp\n"
+ "fnstcw 4(%%rsp)\n"
...

Hairy.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @cpansprout

On Sun Jul 17 09​:49​:29 2016, dcollinsn@​gmail.com wrote​:

dmake minitest reports an expected error in re/reg_mesg.t, a test in
op/glob.t that I'm not sure about (Failed test 16 - ~ works at
op/glob.t line 104)

  ok <>, ' works';

At one point it was broken in miniperl on Unix, which is why the test is there. A simple boolean test is used, as <> will usually return "" on miniperl on Windows.

Glob on miniperl on Windows is implemented in terms of a call to ‘perlglob <arguments>’, and perlglob is provided by the build system. But I don’t know which of the following is used​:

win32/bin/perlglob.pl
win32/perlglob.c

perlglob.pl documents itself as perlglob.bat and a better replacement for perlglob.exe, one that supports wildcards in directory paths.

But perlglob.pl uses File​::DosGlob, which has XS parts, and will consequently fail under miniperl.

I was the one that added the XS parts (partly to fix memory leaks). I am surprised there have not been any bug reports since then. (It never occurred to me that the change would break perlglob.{pl,bat} under miniperl.) It must be that perlglob.c is being used.

What does ‘dir perlglob.*’ give you? What does ‘perlglob ~’ give you?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From @dcollinsn

Zefram​: I don't know how to do that.

Father Chrysostomos​:

W​:\buildbot\windows1\win32ld\build\t>..\miniperl.exe op\glob.t
1..18
ok 1 - leftover op/* files
ok 2 - sane input record separator
ok 3 - glob amid garbage []
ok 4 - input record separator still sane
ok 5 - glob operator 1
ok 6 - glob operator 2
ok 7 - eval'ed a glob 1
ok 8 - eval'ed a glob 2
ok 9 - remove File​::Glob stash
ok 10 - remove File​::Glob stash *and* CORE​::GLOBAL​::glob
ok 11 - undefined *CORE​::GLOBAL​::glob{CODE} at run time
ok 12 - undefined *CORE​::GLOBAL​::glob{CODE} at compile time
ok 13 # skip no File​::Glob to emulate Unix-ism
ok 14 - test definedness with LOGOP
ok 15 - glob globbed something
not ok 16 - ~ works
# Failed test 16 - ~ works at op\glob.t line 104
ok 17 - CORE​::glob bypasses overrides
ok 18 - Make sure the presence of the CORE​::GLOBAL​::glob typeglob does not
affect whether File​::Glob​::csh_glob is called.

W​:\buildbot\windows1\win32ld\build\t>dir perlglob*
Volume in drive W is DATA2TB
Volume Serial Number is BE57-3CFF

Directory of W​:\buildbot\windows1\win32ld\build\t

07/17/2016 12​:30 PM 46,080 perlglob.exe
  1 File(s) 46,080 bytes
  0 Dir(s) 1,119,203,393,536 bytes free

W​:\buildbot\windows1\win32ld\build\t>perlglob.exe ~
~

Without this patch, the test passes. So it might be caused by the fact that
perl is only partly built.

--
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 17, 2016

From zefram@fysh.org

Dan Collins wrote​:

Zefram​: I don't know how to do that.

Add it to embed.fnc, guarded by appropriate #if.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Jul 19, 2016

From @dcollinsn

Submitted to the upstream as https://sourceforge.net/p/mingw/bugs/2306/

This is the patch I'm going to test when I get back to a windows computer. For now it patches in a my_powl on all builds with a mingw.org compiler. No Configure on Windows, so I don't see any way to be smarter about it. Once the upstream is resolved, we can change this to gate on the MinGW version #defines - currently 3.22.

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 19, 2016

From @dcollinsn

0001-RT-128643.patch
From 89699407814eee4c9d12ec8499104e1c8fb9b8ff Mon Sep 17 00:00:00 2001
From: Dan Collins <dcollinsn@gmail.com>
Date: Sun, 17 Jul 2016 12:37:46 -0400
Subject: [PATCH] [RT #128643] Win32: Provide my_powl to replace broken MinGW

The powl() provided by MinGW is broken: under at least some situations,
it fails to overflow from LDBL_MAX to INF. This was noticed because
the test suite uses 9**9**9 as something that "should be" inf, and
MinGW returned LDBL_MAX instead. This patch provides a powl() from
MinGW-w64, conditionally including it whenever long doubles are in
use on a MinGW platform.

This issue has been reported to MinGW as bug #2306. However, in the
interim, this patch allows Perl to build and test successfully on
that platform. Once that ticket is resolved upstream, we can update
core to only provide this function on broken versions of MinGW, for
now, the test is gated on all versions.
---
 embed.fnc     |   3 ++
 embed.h       |   3 ++
 makedef.pl    |   3 ++
 proto.h       |   3 ++
 win32/win32.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 win32/win32.h |  14 ++++++
 6 files changed, 181 insertions(+)

diff --git a/embed.fnc b/embed.fnc
index abc1187..915bbf2 100644
--- a/embed.fnc
+++ b/embed.fnc
@@ -978,6 +978,9 @@ Ap	|I32	|my_pclose	|NULLOK PerlIO* ptr
 Ap	|PerlIO*|my_popen	|NN const char* cmd|NN const char* mode
 #endif
 Ap	|PerlIO*|my_popen_list	|NN const char* mode|int n|NN SV ** args
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32_VERSION_MAJOR) && !defined(__MINGW64_VERSION_MAJOR)
+A	|long double	|my_powl	|long double x|long double y
+#endif
 Ap	|void	|my_setenv	|NULLOK const char* nam|NULLOK const char* val
 Apmb	|I32	|my_stat
 pX	|I32	|my_stat_flags	|NULLOK const U32 flags
diff --git a/embed.h b/embed.h
index b440509..48e1d15 100644
--- a/embed.h
+++ b/embed.h
@@ -894,6 +894,9 @@
 #if defined(USE_LOCALE_COLLATE)
 #define sv_collxfrm_flags(a,b,c)	Perl_sv_collxfrm_flags(aTHX_ a,b,c)
 #endif
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32_VERSION_MAJOR) && !defined(__MINGW64_VERSION_MAJOR)
+#define my_powl(a,b)		my_powl(aTHX_ a,b)
+#endif
 #if defined(USE_PERLIO)
 #define PerlIO_clearerr(a)	Perl_PerlIO_clearerr(aTHX_ a)
 #define PerlIO_close(a)		Perl_PerlIO_close(aTHX_ a)
diff --git a/makedef.pl b/makedef.pl
index 956914e..671d644 100644
--- a/makedef.pl
+++ b/makedef.pl
@@ -561,6 +561,9 @@ if ($define{'PERL_GLOBAL_STRUCT'}) {
     ++$skip{$_} foreach qw(Perl_init_global_struct Perl_free_global_struct);
 }
 
+++$skip{my_powl}
+    unless $define{USE_LONG_DOUBLE} && $define{__MINGW32_VERSION_MAJOR} && !$define{__MINGW64_VERSION_MAJOR};
+
 ++$skip{PL_op_exec_cnt}
     unless $define{PERL_TRACE_OPS};
 
diff --git a/proto.h b/proto.h
index ec2ae33..21c8357 100644
--- a/proto.h
+++ b/proto.h
@@ -5808,6 +5808,9 @@ PERL_CALLCONV char*	Perl_sv_collxfrm_flags(pTHX_ SV *const sv, STRLEN *const nxp
 #define PERL_ARGS_ASSERT_SV_COLLXFRM_FLAGS	\
 	assert(sv); assert(nxp)
 #endif
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32_VERSION_MAJOR) && !defined(__MINGW64_VERSION_MAJOR)
+PERL_CALLCONV long double	my_powl(pTHX_ long double x, long double y);
+#endif
 #if defined(USE_PERLIO)
 PERL_CALLCONV void	Perl_PerlIO_clearerr(pTHX_ PerlIO *f);
 PERL_CALLCONV int	Perl_PerlIO_close(pTHX_ PerlIO *f);
diff --git a/win32/win32.c b/win32/win32.c
index 6ac73e2..20a28e5 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -4795,3 +4795,158 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
 }
 #  endif /* USE_ITHREADS */
 #endif /* HAVE_INTERP_INTERN */
+
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32_VERSION_MAJOR) && !defined(__MINGW64_VERSION_MAJOR)
+/* NAN builtins for gcc, as they are not part of math.h  */
+#ifndef NANF
+#define NANF __builtin_nanf ("")
+#endif
+#ifndef NANL
+#define NANL __builtin_nanl ("")
+#endif
+
+
+#ifndef _SET_ERRNO
+#define _SET_ERRNO(x) errno = (x)
+#endif
+
+
+static long double
+internal_modf (long double value, long double *iptr)
+{
+  long double int_part = (long double) 0.0;
+#ifdef _WIN64
+  asm ("pushq %%rax\n\tsubq $8, %%rsp\n"
+    "fnstcw 4(%%rsp)\n"
+    "movzwl 4(%%rsp), %%eax\n"
+    "orb $12, %%ah\n"
+    "movw %%ax, (%%rsp)\n"
+    "fldcw (%%rsp)\n"
+    "frndint\n"
+    "fldcw 4(%%rsp)\n"
+    "addq $8, %%rsp\npopq %%rax" : "=t" (int_part) : "0" (value)); /* round */
+#else
+  asm ("push %%eax\n\tsubl $8, %%esp\n"
+    "fnstcw 4(%%esp)\n"
+    "movzwl 4(%%esp), %%eax\n"
+    "orb $12, %%ah\n"
+    "movw %%ax, (%%esp)\n"
+    "fldcw (%%esp)\n"
+    "frndint\n"
+    "fldcw 4(%%esp)\n"
+    "addl $8, %%esp\n\tpop %%eax\n" : "=t" (int_part) : "0" (value)); /* round */
+#endif
+  if (iptr)
+    *iptr = int_part;
+  return (isinf (value) ?  (long double) 0.0 : value - int_part);
+}
+
+long double __powil (long double x, int n);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+long double __cdecl
+my_powl (long double x, long double y)
+{
+  int x_class = fpclassify (x);
+  int y_class = fpclassify (y);
+  long odd_y = 0;
+  long double d, rslt;
+
+  if (y_class == FP_ZERO || x == 1.0L)
+    return 1.0L;
+  else if (x_class == FP_NAN || y_class == FP_NAN)
+    {
+      rslt = (signbit(x) ? -NANL : NANL);
+      _SET_ERRNO (EDOM);
+      return rslt;
+    }
+  else if (x_class == FP_ZERO)
+    {
+      if (y_class == FP_INFINITE)
+        return (signbit(y) ? HUGE_VALL : 0.0L);
+
+      if (signbit(x) && internal_modf (y, &d) != 0.0)
+        {
+          return signbit (y) ? (1.0 / -x) : 0.0L;
+        }
+      odd_y = (internal_modf (ldexpl (y, -1), &d) != 0.0) ? 1 : 0;
+      if (!signbit(y))
+        {
+          if (!odd_y || !signbit (x))
+            return 0.0L;
+          return -0.0L;
+        }
+
+      if (!odd_y || !signbit (x))
+        return HUGE_VALL;
+      return (signbit(x) ? -HUGE_VALL : HUGE_VALL);
+    }
+  else if (y_class == FP_INFINITE)
+    {
+      long double a_x;
+
+      if (x_class == FP_INFINITE)
+        return (signbit (y) ? 0.0L : HUGE_VALL);
+      a_x = (signbit (x) ? -x : x);
+      if (a_x == 1.0)
+        return 1.0L;
+      if (a_x > 1.0)
+        return (signbit (y) == 0 ? HUGE_VALL : 0.0L);
+      return (!signbit (y) ? 0.0L : HUGE_VALL);
+    }
+  else if (x_class == FP_INFINITE)
+    {
+      /* pow (x, y) signals the invalid operation exception for finite x < 0 and finite non-integer y.  */
+      if (signbit(x) && internal_modf (y, &d) != 0.0)
+        {
+          return signbit(y) ? 1.0 / -x : -x;
+        }
+      odd_y = (internal_modf (ldexpl (y, -1), &d) != 0.0) ? 1 : 0;
+      /* pow( -inf, y) = +0 for y<0 and not an odd integer,  */
+      if (signbit(x) && signbit(y) && !odd_y)
+        return 0.0L;
+      /* pow( -inf, y) = -inf for y an odd integer > 0.  */
+      if (signbit(x) && !signbit(y) && odd_y)
+        return -HUGE_VALL;
+      /* pow( -inf, y) = +inf for y>0 and not an odd integer.  */
+      if (signbit(x) && !signbit(y) && !odd_y)
+        return HUGE_VALL;
+      /* pow (+/-inf, y) is +/-0 with no exception for y an odd integer < 0. */
+      if (signbit(y))
+      {
+        /* pow (+/-inf, y) is +0 with no exception for finite y < 0 and not an odd integer.  */
+        return (odd_y && signbit(x) ? -0.0L : 0.0L);
+      }
+      /* pow (+/-inf, y) is +/-inf with no exception for finite y > 0 an odd integer.  */
+      /* pow (+/-inf, y) is +inf with no exception for finite y > 0 and not an odd integer.  */
+      return (odd_y && signbit(x) ? -HUGE_VALL : HUGE_VALL);
+    }
+
+  if (internal_modf (y, &d) != 0.0)
+    {
+      if (signbit (x))
+        {
+          _SET_ERRNO (EDOM);
+          return -NANL;
+        }
+      if (y == 0.5L)
+        {
+          asm ("fsqrt" : "=t" (rslt) : "0" (x));
+          return rslt;
+        }
+    }
+  else if ((d <= (long double) INT_MAX && d >= (long double) INT_MIN))
+     return __powil (x, (int) y);
+  /* As exp already checks for minlog and maxlog no further checks are necessary.  */
+  rslt = (long double) exp2l ((long double) y * log2l ((long double) fabsl (x)));
+
+  if (signbit (x) && internal_modf (ldexpl (y, -1), &d) != 0.0)
+    rslt = -rslt;
+  return rslt;
+}
+#ifdef __cplusplus
+}
+#endif
+#endif
\ No newline at end of file
diff --git a/win32/win32.h b/win32/win32.h
index 9b79e00..1d1dbb0 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -662,5 +662,19 @@ DllExport void *win32_signal_context(void);
 #define Win_CreateSemaphore   CreateSemaphore
 #endif
 
+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32_VERSION_MAJOR) && !defined(__MINGW64_VERSION_MAJOR)
+/* MinGW.org provides a powl that is broken: 9**9**9 returns
+ * LDBL_MAX instead of INF.
+ */
+#define powl my_powl
+#ifdef __cplusplus
+extern "C" {
+#endif
+long double __cdecl my_powl (long double x, long double y);
+#ifdef __cplusplus
+}
+#endif
+#endif
+
 #endif /* _INC_WIN32_PERL5 */
 
-- 
2.8.3

@p5pRT
Copy link
Author

p5pRT commented Jul 20, 2016

From @sisyphus

-----Original Message-----
From​: Dan Collins via RT
Sent​: Wednesday, July 20, 2016 12​:19 AM
To​: OtherRecipients of perl Ticket #128643​:
Cc​: perl5-porters@​perl.org
Subject​: [perl #128643] MinGW.org builds - infnan and pack test failures due
to LD handling

Submitted to the upstream as https://sourceforge.net/p/mingw/bugs/2306/

This is the patch I'm going to test when I get back to a windows computer.
For now it patches in a my_powl on all builds with a mingw.org compiler.
No Configure on Windows, so I don't see any way to be smarter about it.
Once the upstream is resolved, we can change this to gate on the MinGW
version #defines - currently 3.22.

[snip]

+#if defined(USE_LONG_DOUBLE) && defined(__MINGW32_VERSION_MAJOR) &&
!defined(__MINGW64_VERSION_MAJOR)

My mingw.org compiler does not define the second symbol
(__MINGW32_VERSION_MAJOR), though both mingw.org and mingw-w64 do define
__MINGW32_MAJOR_VERSION.

I *think* the info provided at
https://sourceforge.net/p/predef/wiki/Compilers/ for "MinGW and MinGW-w64 is
accurate.

Cheers,
Rob

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants