https://git.reactos.org/?p=reactos.git;a=commitdiff;h=bd0a28d1e41171a536129…
commit bd0a28d1e41171a5361292e52c745bc8e48d3dde
Author: Colin Finck <colin(a)reactos.org>
AuthorDate: Fri Mar 1 17:49:03 2019 +0100
Commit: Hermès BÉLUSCA - MAÏTO <hermes.belusca-maito(a)reactos.org>
CommitDate: Sun Mar 3 16:11:27 2019 +0100
Fix the MSVC version of ldexp filling up the FPU stack and bailing out with #IND after
a few calls. Additionally, add it back to libcntpr.
MSVC was previously given a "result" variable to copy the fscale result from
st(0). This led to another "fld" FPU stack push at the very end without popping
the source value from the FPU stack.
Moreover, this copy isn't even needed: A simple "fstp st(1)" at the end
pops an element from the FPU stack while effectively storing the result in st(0), the
register used for returning a double value.
This problem didn't affect GCC, as it is only given the "fscale"
instruction and does all necessary stack operations itself.
However, looking into the CRT sources, I found many other i386 implementations with
inline assembly suffering from the same problem.
Fortunately, they have been replaced by pure assembly implementations a while ago, so
it's time to finally remove them.
ldexp would have also been a candidate for a pure assembly implementation, but the
required check for NaN and setting errno (verified on Win2003) already outweighs the
benefits.
And we cannot just do a NaN check with FUCOMI as this is an i686/pentiumpro
instruction while we're still targeting i586/pentium.
I'm also using this opportunity to clean up the ldexp.c header and only put in the
remaining contributors as returned by "git blame".
Thanks to NightWolve1975 for reporting the problem!
(
https://twitter.com/nightwolve1975/status/1099042477531643912)
---
sdk/lib/crt/libcntpr.cmake | 3 +-
sdk/lib/crt/math/i386/atan2.c | 27 ------------------
sdk/lib/crt/math/i386/exp.c | 64 -------------------------------------------
sdk/lib/crt/math/i386/fmod.c | 49 ---------------------------------
sdk/lib/crt/math/i386/fmodf.c | 28 -------------------
sdk/lib/crt/math/i386/ldexp.c | 45 ++++++++++++------------------
6 files changed, 19 insertions(+), 197 deletions(-)
diff --git a/sdk/lib/crt/libcntpr.cmake b/sdk/lib/crt/libcntpr.cmake
index 8014bd370e..aa3b1d4fa6 100644
--- a/sdk/lib/crt/libcntpr.cmake
+++ b/sdk/lib/crt/libcntpr.cmake
@@ -105,7 +105,8 @@ if(ARCH STREQUAL "i386")
math/i386/cilog.c
math/i386/cipow.c
math/i386/cisin.c
- math/i386/cisqrt.c)
+ math/i386/cisqrt.c
+ math/i386/ldexp.c)
if(NOT MSVC)
list(APPEND LIBCNTPR_SOURCE except/i386/chkstk_ms.s)
endif()
diff --git a/sdk/lib/crt/math/i386/atan2.c b/sdk/lib/crt/math/i386/atan2.c
deleted file mode 100644
index 7b7ebac8a2..0000000000
--- a/sdk/lib/crt/math/i386/atan2.c
+++ /dev/null
@@ -1,27 +0,0 @@
-
-#include <math.h>
-
-double atan2 (double __y, double __x);
-
-/*
- * @implemented
- */
-double atan2 (double __y, double __x)
-{
- register double __val;
-#ifdef __GNUC__
- __asm __volatile__
- ("fpatan\n\t"
- "fld %%st(0)"
- : "=t" (__val) : "0" (__x), "u" (__y));
-#else
- __asm
- {
- fld __y
- fld __x
- fpatan
- fstp __val
- }
-#endif /*__GNUC__*/
- return __val;
-}
diff --git a/sdk/lib/crt/math/i386/exp.c b/sdk/lib/crt/math/i386/exp.c
deleted file mode 100644
index 727a1cb541..0000000000
--- a/sdk/lib/crt/math/i386/exp.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Math functions for i387.
- Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by John C. Bowman <bowman(a)ipp-garching.mpg.de>de>, 1995.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include <math.h>
-
-double exp (double __x);
-
-double exp (double __x)
-{
-#ifdef __GNUC__
- register double __value, __exponent;
- __asm __volatile__
- ("fldl2e # e^x = 2^(x * log2(e))\n\t"
- "fmul %%st(1) # x * log2(e)\n\t"
- "fst %%st(1)\n\t"
- "frndint # int(x * log2(e))\n\t"
- "fxch\n\t"
- "fsub %%st(1) # fract(x * log2(e))\n\t"
- "f2xm1 # 2^(fract(x * log2(e))) - 1\n\t"
- : "=t" (__value), "=u" (__exponent) : "0" (__x));
- __value += 1.0;
- __asm __volatile__
- ("fscale"
- : "=t" (__value) : "0" (__value), "u" (__exponent));
-
- return __value;
-#else
- register double __val;
- __asm
- {
- fld1 // store 1.0 for later use
- fld __x
- fldl2e // e^x = 2^(x * log2(e))
- fmul st,st(1) // x * log2(e)
- fld st(0)
- frndint // int(x * log2(e))
- fsub st,st(1) // fract(x * log2(e))
- fxch
- f2xm1 // 2^(fract(x * log2(e))) - 1
- fadd st,st(3) // + 1.0
- fscale
- fstp __val
- }
- return __val;
-#endif /*__GNUC__*/
-}
diff --git a/sdk/lib/crt/math/i386/fmod.c b/sdk/lib/crt/math/i386/fmod.c
deleted file mode 100644
index fe74aa5e4d..0000000000
--- a/sdk/lib/crt/math/i386/fmod.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Math functions for i387.
- Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by John C. Bowman <bowman(a)ipp-garching.mpg.de>de>, 1995.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
-
-#include <math.h>
-
-double fmod (double __x, double __y);
-
-double fmod (double __x, double __y)
-{
- register double __val;
-#ifdef __GNUC__
- __asm __volatile__
- ("1: fprem\n\t"
- "fstsw %%ax\n\t"
- "sahf\n\t"
- "jp 1b"
- : "=t" (__val) : "0" (__x), "u" (__y) :
"ax", "cc");
-#else
- __asm
- {
- fld __y
- fld __x
-L1: fprem1
- fstsw ax
- sahf
- jp L1
- fstp __val
- }
-#endif /*__GNUC__*/
- return __val;
-}
diff --git a/sdk/lib/crt/math/i386/fmodf.c b/sdk/lib/crt/math/i386/fmodf.c
deleted file mode 100644
index 761f56c043..0000000000
--- a/sdk/lib/crt/math/i386/fmodf.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/**
- * This file has no copyright assigned and is placed in the Public Domain.
- * This file is part of the w64 mingw-runtime package.
- * No warranty is given; refer to the file DISCLAIMER.PD within this package.
- */
-/*
- * Written by J.T. Conklin <jtc(a)netbsd.org>rg>.
- * Public domain.
- *
- * Adapted for float type by Danny Smith
- * <dannysmith(a)users.sourceforge.net>et>.
- */
-
-#include <math.h>
-
-float
-fmodf (float x, float y)
-{
- float res = 0.0F;
-
- asm ("1:\tfprem\n\t"
- "fstsw %%ax\n\t"
- "sahf\n\t"
- "jp 1b\n\t"
- "fstp %%st(1)"
- : "=t" (res) : "0" (x), "u" (y) : "ax",
"st(1)");
- return res;
-}
diff --git a/sdk/lib/crt/math/i386/ldexp.c b/sdk/lib/crt/math/i386/ldexp.c
index 48cbc751d6..73d3e92772 100644
--- a/sdk/lib/crt/math/i386/ldexp.c
+++ b/sdk/lib/crt/math/i386/ldexp.c
@@ -1,33 +1,18 @@
-/* Math functions for i387.
- Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by John C. Bowman <bowman(a)ipp-garching.mpg.de>de>, 1995.
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- The GNU C Library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-*/
+/*
+ * PROJECT: ReactOS CRT
+ * LICENSE: LGPL-2.1-or-later (
https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE: Implements the ldexp CRT function for IA-32 with Windows-compatible error
codes.
+ * COPYRIGHT: Copyright 2010 Timo Kreuzer (timo.kreuzer(a)reactos.org)
+ * Copyright 2011 Pierre Schweitzer (pierre(a)reactos.org)
+ * Copyright 2019 Colin Finck (colin(a)reactos.org)
+ */
#include <precomp.h>
-#include <math.h>
-#include <float.h>
double ldexp (double value, int exp)
{
+#ifdef __GNUC__
register double result;
-#ifndef __GNUC__
- register double __dy = (double)exp;
#endif
/* Check for value correctness
@@ -43,15 +28,19 @@ double ldexp (double value, int exp)
: "=t" (result)
: "0" (value), "u" ((double)exp)
: "1");
+ return result;
#else /* !__GNUC__ */
__asm
{
- fld __dy
+ fild exp
fld value
fscale
- fstp result
+ fstp st(1)
}
+
+ /* "fstp st(1)" has copied st(0) to st(1), then popped the FPU stack,
+ * so that the value is again in st(0) now. Effectively, we have reduced
+ * the FPU stack by one element while preserving st(0).
+ * st(0) is also the register used for returning a double value. */
#endif /* !__GNUC__ */
- return result;
}
-