]> Savannah Git Hosting - gnulib.git/commitdiff
fenv-rounding: New module.
authorBruno Haible <bruno@clisp.org>
Fri, 27 Oct 2023 18:16:50 +0000 (20:16 +0200)
committerBruno Haible <bruno@clisp.org>
Fri, 27 Oct 2023 18:26:31 +0000 (20:26 +0200)
* lib/fenv.in.h (fegetround, fesetround): New declarations.
* lib/fenv-private.h: New file, based on glibc.
* lib/fenv-round.c: New file, based on glibc.
* m4/mathfunc.m4 (gl_MATHFUNC): Handle also the type fp_rnd.
* m4/fenv-rounding.m4: New file.
* modules/fenv (Depends-on): Add snippet/c++defs.
(Makefile.am): Substitute $(CXXDEFS_H) into fenv.h.
* modules/fenv-rounding: New file.
* doc/posix-functions/fegetround.texi: Mention the new module.
* doc/posix-functions/fesetround.texi: Likewise.

ChangeLog
doc/posix-functions/fegetround.texi
doc/posix-functions/fesetround.texi
lib/fenv-private.h [new file with mode: 0644]
lib/fenv-round.c [new file with mode: 0644]
lib/fenv.in.h
m4/fenv-rounding.m4 [new file with mode: 0644]
m4/mathfunc.m4
modules/fenv
modules/fenv-rounding [new file with mode: 0644]

index 1b0201ce6ca1e198f5be1693b3ef39f6e9243bc0..b4c109b02a6c4d61b85d1f4154a713888fb4179f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2023-10-27  Bruno Haible  <bruno@clisp.org>
+
+       fenv-rounding: New module.
+       * lib/fenv.in.h (fegetround, fesetround): New declarations.
+       * lib/fenv-private.h: New file, based on glibc.
+       * lib/fenv-round.c: New file, based on glibc.
+       * m4/mathfunc.m4 (gl_MATHFUNC): Handle also the type fp_rnd.
+       * m4/fenv-rounding.m4: New file.
+       * modules/fenv (Depends-on): Add snippet/c++defs.
+       (Makefile.am): Substitute $(CXXDEFS_H) into fenv.h.
+       * modules/fenv-rounding: New file.
+       * doc/posix-functions/fegetround.texi: Mention the new module.
+       * doc/posix-functions/fesetround.texi: Likewise.
+
 2023-10-27  Bruno Haible  <bruno@clisp.org>
 
        tests: Use C99 initializer syntax for memory_long_double.
index 869698131ffd133fd139280c4d3f50eab603b3f2..c32eb4230ec044fabe6889f318c44e87e2497fbf 100644 (file)
@@ -4,15 +4,15 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/fegetround.html}
 
-Gnulib module: ---
+Gnulib module: fenv-rounding
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function is missing on some platforms:
-FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4.
 @end itemize
index 2efc18f31f96e7d2a2c330e870c891088dd09d10..f0c74c346787f751d04cdd7d5b75cd52997c302f 100644 (file)
@@ -4,15 +4,18 @@
 
 POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/fesetround.html}
 
-Gnulib module: ---
+Gnulib module: fenv-rounding
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4.
+@item
+This function does not work on some platforms:
+MSVC 14.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function is missing on some platforms:
-FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4.
 @end itemize
diff --git a/lib/fenv-private.h b/lib/fenv-private.h
new file mode 100644 (file)
index 0000000..286768c
--- /dev/null
@@ -0,0 +1,379 @@
+/* Common definitions for the implementation of the various <fenv.h> modules.
+   Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+   This file 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.
+
+   This file 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 this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Based on glibc/sysdeps/<cpu>/{fpu_control.h,fenv_private.h,fenv_libc.h}.  */
+
+#if (defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)
+
+# if !(defined __x86_64__ || defined _M_X64)
+#  if __GLIBC__ + (__GLIBC_MINOR__ >= 33) > 2
+/* glibc >= 2.33 has an API that tells us whether the CPU has an SSE unit.  */
+#   include <sys/platform/x86.h>
+#  elif defined __sun
+/* Solaris has a global variable that tells us whether the CPU has an SSE unit.  */
+extern int _sse_hw;
+#  endif
+# endif
+
+/* CPU_HAS_SSE ()  returns true if the CPU has an SSE unit.  */
+# if defined __x86_64__ || defined _M_X64
+#  define CPU_HAS_SSE() 1
+# else
+#  if __GLIBC__ + (__GLIBC_MINOR__ >= 33) > 2
+#   define CPU_HAS_SSE() CPU_FEATURE_PRESENT (SSE)
+#  elif defined __sun
+#   define CPU_HAS_SSE() _sse_hw
+#  else
+/* Otherwise, we assume that the SSE unit is present.
+   Only very old 32-bit processors, before Pentium 4, don't have it.
+   Don't bother testing it, through a 'cpuid' instruction.  */
+#   define CPU_HAS_SSE() 1
+#  endif
+# endif
+
+/* fstat bits 5..2,0 indicate which floating-point exceptions have occurred
+   in the 387 compatible floating-point unit since the respective bit was last
+   set to zero.
+   mxcsr bits 5..2,0 indicate which floating-point exceptions have occurred
+   in the SSE floating-point unit since the respective bit was last set to
+   zero.  */
+/* fctrl bits 5..2,0 indicate which floating-point exceptions shall, when
+   occurring in the 387 compatible floating-point unit, *not* trigger a trap
+   rather than merely set the corresponding bit in the fstat register.
+   mxcsr bits 12..9,7 indicate which floating-point exceptions shall, when
+   occurring in the SSE floating-point unit, *not* trigger a trap rather
+   than merely set the corresponding bit in the mxcsr register.  */
+
+/* Macros that access the control word of the 387 unit, the so-called fctrl
+   register.  */
+# define _FPU_GETCW(cw) __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw))
+# define _FPU_SETCW(cw) __asm__ __volatile__ ("fldcw %0" : : "m" (*&cw))
+
+/* Macros that access the status word of the 387 unit, the so-called fstat
+   register.  */
+# define _FPU_GETSTAT(cw) __asm__ __volatile__ ("fnstsw %0" : "=m" (*&cw))
+
+/* Macros that access the control and status word of the SSE unit, the mxcsr
+   register.  */
+# if defined __GNUC__ || defined __clang__
+#  define _FPU_GETSSECW(cw) __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&cw))
+#  define _FPU_SETSSECW(cw) __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&cw))
+# elif defined _MSC_VER
+#  include <mmintrin.h>
+/* Documentation:
+   <https://learn.microsoft.com/en-us/cpp/intrinsics/x86-intrinsics-list>
+   <https://learn.microsoft.com/en-us/cpp/intrinsics/x64-amd64-intrinsics-list>
+   <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_getcsr&ig_expand=3548>
+   <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_setcsr&ig_expand=5924>
+ */
+#  define _FPU_GETSSECW(cw) ((cw) = _mm_getcsr ())
+#  define _FPU_SETSSECW(cw) _mm_setcsr (cw)
+# endif
+
+/* The floating-point environment of the 387 unit.  */
+typedef struct
+  {
+    /* 7 32-bit words:  */
+    unsigned short __control_word;      /* fctrl register */
+    unsigned short __reserved1;
+    unsigned short __status_word;       /* fstat register */
+    unsigned short __reserved2;
+    unsigned int more[5];
+  }
+x86_387_fenv_t;
+
+# if defined _MSC_VER
+/* The MSVC header files have different values for the floating-point exceptions
+   than all the other platforms.  Define some handy macros for conversion.  */
+#  define exceptions_to_x86hardware(exceptions) \
+     (  ((exceptions) & FE_INVALID   ? 0x01 : 0) \
+      | ((exceptions) & FE_DIVBYZERO ? 0x04 : 0) \
+      | ((exceptions) & FE_OVERFLOW  ? 0x08 : 0) \
+      | ((exceptions) & FE_UNDERFLOW ? 0x10 : 0) \
+      | ((exceptions) & FE_INEXACT   ? 0x20 : 0))
+#  define x86hardware_to_exceptions(fstat) \
+     (  ((fstat) & 0x01 ? FE_INVALID   : 0) \
+      | ((fstat) & 0x04 ? FE_DIVBYZERO : 0) \
+      | ((fstat) & 0x08 ? FE_OVERFLOW  : 0) \
+      | ((fstat) & 0x10 ? FE_UNDERFLOW : 0) \
+      | ((fstat) & 0x20 ? FE_INEXACT   : 0))
+# else
+#  define exceptions_to_x86hardware(exceptions) (exceptions)
+#  define x86hardware_to_exceptions(fstat) (fstat)
+# endif
+
+/* When _MSC_VER is defined, the 387 compatible floating-point unit is *not*
+   in use.  Only the SSE floating-point unit is used.  This can be inferred
+   from two facts:
+     - sizeof (long double) == sizeof (double).  That is, 'long double'
+       values are just 'double' values and can be processed in the SSE unit.
+     - After fegetenv (&env), the value of env._Fe_stat is *not* the fstat
+       register of the 387 unit.  Rather, it is a artificial value.  In
+       particular, (env._Fe_stat & 0x3f) is
+       == x86hardware_to_exceptions (_FPU_GETSSECW () & 0x3f).  */
+
+#elif defined __aarch64__ /* arm64 */
+
+/* fpsr bits 4..0 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+/* fpcr bits 12..8 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fpsr register.  */
+
+# if __GNUC__ >= 6
+#  define _FPU_GETCW(fpcr) (fpcr = __builtin_aarch64_get_fpcr ())
+#  define _FPU_SETCW(fpcr) __builtin_aarch64_set_fpcr (fpcr)
+# else
+#  define _FPU_GETCW(fpcr) \
+   __asm__ __volatile__ ("mrs %0, fpcr" : "=r" (fpcr))
+#  define _FPU_SETCW(fpcr) \
+   __asm__ __volatile__ ("msr fpcr, %0" : : "r" (fpcr))
+# endif
+
+# if __GNUC__ >= 6
+#  define _FPU_GETFPSR(fpsr) (fpsr = __builtin_aarch64_get_fpsr ())
+#  define _FPU_SETFPSR(fpsr) __builtin_aarch64_set_fpsr (fpsr)
+# else
+#  define _FPU_GETFPSR(fpsr) \
+   __asm__ __volatile__ ("mrs %0, fpsr" : "=r" (fpsr))
+#  define _FPU_SETFPSR(fpsr) \
+   __asm__ __volatile__ ("msr fpsr, %0" : : "r" (fpsr))
+# endif
+
+#elif defined __arm__
+
+/* fpscr bits 23..22 indicate the rounding direction.  */
+/* fpscr bits 4..0 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+/* fpscr bits 12..8 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fpscr register.  */
+
+# if !defined __SOFTFP__
+#  define _FPU_GETCW(cw) \
+   __asm__ __volatile__ ("vmrs %0, fpscr" : "=r" (cw))
+#  define _FPU_SETCW(cw) \
+   __asm__ __volatile__ ("vmsr fpscr, %0" : : "r" (cw))
+# endif
+
+#elif defined __alpha
+
+/* System calls.  */
+extern unsigned long __ieee_get_fp_control (void);
+extern void __ieee_set_fp_control (unsigned long);
+
+# define _FPU_GETCW(fpcr) \
+  __asm__ __volatile__ ("excb; mf_fpcr %0" : "=f" (fpcr))
+# define _FPU_SETCW(fpcr) \
+  __asm__ __volatile__ ("mt_fpcr %0; excb" : : "f" (fpcr))
+
+#elif defined __hppa
+
+/* Bits 31..27 of the first 32-bit word of %fr0 indicate which floating-point
+   exceptions have occurred since the respective bit was last set to zero.  */
+/* Bits 4..0 of the first 32-bit word of %fr0 indicate which floating-point
+   exceptions shall, when occurring, trigger a trap rather than merely set the
+   corresponding flag bit.  */
+
+/* The status register is located in bits 0 to 31 of floating-point register 0.  */
+# define _FPU_GETCW(cw) \
+({                                                                              \
+  union { __extension__ unsigned long long __fpreg; unsigned int __halfreg[2]; } __fullfp; \
+  /* Get the current status word. */                                            \
+  __asm__ ("fstd %%fr0,0(%1)\n\t"                                               \
+           "fldd 0(%1),%%fr0\n\t"                                               \
+           : "=m" (__fullfp.__fpreg) : "r" (&__fullfp.__fpreg) : "%r0");        \
+  cw = __fullfp.__halfreg[0];                                                   \
+})
+# define _FPU_SETCW(cw) \
+({                                                                              \
+  union { __extension__ unsigned long long __fpreg; unsigned int __halfreg[2]; } __fullfp; \
+  /* Get the current status word and set the control word.  */                  \
+  __asm__ ("fstd %%fr0,0(%1)\n\t"                                               \
+           : "=m" (__fullfp.__fpreg) : "r" (&__fullfp.__fpreg) : "%r0");        \
+  __fullfp.__halfreg[0] = cw;                                                   \
+  __asm__ ("fldd 0(%1),%%fr0\n\t"                                               \
+           : : "m" (__fullfp.__fpreg), "r" (&__fullfp.__fpreg) : "%r0" );       \
+})
+
+#elif defined __ia64__
+
+/* fpsr bits 12..9,7 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+/* fpsr bits 5..2,0 indicate which floating-point exceptions shall, when
+   occurring, *not* trigger a trap rather than merely set the corresponding
+   bit in the fpsr register.  */
+
+# define _FPU_GETCW(fpsr) \
+  __asm__ __volatile__ ("mov.m %0=ar.fpsr" : "=r" (fpsr))
+# define _FPU_SETCW(fpsr) \
+  __asm__ __volatile__ ("mov.m ar.fpsr=%0" :: "r" (fpsr) : "memory")
+
+#elif defined __m68k__
+
+/* fpsr bits 7..3 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+/* fpcr bits 15..8 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fpsr register:
+     - bit 15: branch/set on unordered
+     - bit 14: signaling not-a-number
+     - bit 13: operand error
+     - bit 12: overflow
+     - bit 11: underflow
+     - bit 10: divide by zero
+     - bit 9:  inexact operation
+     - bit 8:  inexact decimal input
+   FE_INVALID corresponds to all three: bit 15, bit 14, bit 13.  */
+
+# define _FPU_GETCW(cw) __asm__ __volatile__ ("fmove%.l %!, %0" : "=dm" (cw))
+# define _FPU_SETCW(cw) __asm__ __volatile__ ("fmove%.l %0, %!" : : "dm" (cw))
+
+# define _FPU_GETFPSR(cw) __asm__ __volatile__ ("fmove%.l %/fpsr, %0" : "=dm" (cw))
+# define _FPU_SETFPSR(cw) __asm__ __volatile__ ("fmove%.l %0, %/fpsr" : : "dm" (cw))
+
+#elif defined __mips__
+
+/* fcsr bits 6..2 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.
+   fcsr bits 17..12 indicate which floating-point exceptions have occurred
+   in the most recent instruction.  */
+/* fcsr bits 11..7 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fcsr register.  */
+
+# define _FPU_GETCW(cw) __asm__ __volatile__ ("cfc1 %0,$31" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ __volatile__ ("ctc1 %0,$31" : : "r" (cw))
+
+#elif defined __loongarch__
+
+/* fcsr0 bits 20..16 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.
+   fcsr0 bits 28..24 indicate which floating-point exceptions have occurred
+   in the most recent instruction.  */
+/* fcsr0 bits 4..0 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fcsr0 register.  */
+
+# define _FPU_GETCW(cw) __asm__ __volatile__ ("movfcsr2gr %0,$r0" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ __volatile__ ("movgr2fcsr $r0,%0" : : "r" (cw))
+
+#elif defined __powerpc__
+
+/* fpscr bits 28..25 indicate which floating-point exceptions, other than
+   FE_INVALID, have occurred since the respective bit was last set to zero.
+   fpscr bits 24..19, 10..8 do the same thing, for various kinds of Invalid
+   Operation.  fpscr bit 29 is the summary (the OR) of all these bits.  */
+/* fpscr bits 7..3 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fpscr register.  */
+
+# define _FPU_GETCW_AS_DOUBLE(cw) \
+  do { double env; __asm__ __volatile__ ("mffs %0" : "=f" (env)); cw = env; } \
+  while (0)
+# define _FPU_SETCW_AS_DOUBLE(cw) \
+  __asm__ __volatile__ ("mtfsf 0xff,%0" : : "f" (cw))
+
+#elif defined __riscv
+
+/* fcsr bits 4..0 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+
+/* Trapping of floating-point exceptions does not work on RISC-V.  That's
+   because the fcsr register has only bits for floating-point exception status,
+   but no bits for trapping floating-point exceptions.  */
+
+#elif defined __s390__ || defined __s390x__
+
+/* fpc bits 23..19 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.
+   fpc bits 15..11 are part of the "data exception code" (DXC) and have a
+   similar meaning if bits 9..8 are both zero.  */
+/* fpc bits 31..27 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fpc register.  */
+
+# define _FPU_GETCW(cw)  __asm__ __volatile__ ("efpc %0" : "=d" (cw))
+# define _FPU_SETCW(cw)  __asm__ __volatile__ ("sfpc %0" : : "d" (cw))
+
+#elif defined __sh__
+
+/* fpscr bits 6..2 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+/* fpscr bits 11..7 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fpscr register.  */
+
+# define _FPU_GETCW(cw) __asm__ ("sts fpscr,%0" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ ("lds %0,fpscr" : : "r" (cw))
+
+#elif defined __sparc
+
+/* fsr bits 9..5 indicate which floating-point exceptions have occurred
+   since the respective bit was last set to zero.  */
+/* fsr bits 27..23 indicate which floating-point exceptions shall, when
+   occurring, trigger a trap rather than merely set the corresponding bit
+   in the fsr register.  */
+
+# if defined __sparcv9 || defined __arch64__ /* sparc64 */
+#  define _FPU_GETCW(X)   __asm__ __volatile__ ("stx %%fsr,%0" : "=m" (X))
+#  define _FPU_SETCW(X)   __asm__ __volatile__ ("ldx %0,%%fsr" : : "m" (X))
+# else
+#  define _FPU_GETCW(X)   __asm__ __volatile__ ("st %%fsr,%0" : "=m" (X))
+#  define _FPU_SETCW(X)   __asm__ __volatile__ ("ld %0,%%fsr" : : "m" (X))
+# endif
+
+#endif
+
+#if defined _AIX && defined __powerpc__ /* AIX */
+
+/* <fpxcp.h> defines a type fpflag_t and macros FP_*.  */
+
+/* Convert from an 'int exceptions' to an fpflag_t.  */
+# if 0 /* Unoptimized */
+#  define exceptions_to_fpflag(exceptions) \
+     (  ((exceptions) & FE_INVALID   ? FP_INVALID     : 0) \
+      | ((exceptions) & FE_DIVBYZERO ? FP_DIV_BY_ZERO : 0) \
+      | ((exceptions) & FE_OVERFLOW  ? FP_OVERFLOW    : 0) \
+      | ((exceptions) & FE_UNDERFLOW ? FP_UNDERFLOW   : 0) \
+      | ((exceptions) & FE_INEXACT   ? FP_INEXACT     : 0))
+# else /* Optimized */
+#  define exceptions_to_fpflag(exceptions) \
+     ((exceptions) & FE_ALL_EXCEPT)
+# endif
+
+/* Convert from an fpflag_t to an 'int exceptions'.  */
+# if 0 /* Unoptimized */
+#  define fpflag_to_exceptions(f) \
+     (  ((f) & FP_INVALID     ? FE_INVALID   : 0) \
+      | ((f) & FP_DIV_BY_ZERO ? FE_DIVBYZERO : 0) \
+      | ((f) & FP_OVERFLOW    ? FE_OVERFLOW  : 0) \
+      | ((f) & FP_UNDERFLOW   ? FE_UNDERFLOW : 0) \
+      | ((f) & FP_INEXACT     ? FE_INEXACT   : 0))
+# else /* Optimized */
+#  define fpflag_to_exceptions(f) \
+     ((f) & FE_ALL_EXCEPT)
+# endif
+
+/* The implementation of fegetexcept().  Avoids a module dependency.  */
+# define fegetexcept_impl() \
+    (  (fp_is_enabled (TRP_INVALID)     ? FE_INVALID   : 0) \
+     | (fp_is_enabled (TRP_DIV_BY_ZERO) ? FE_DIVBYZERO : 0) \
+     | (fp_is_enabled (TRP_OVERFLOW)    ? FE_OVERFLOW  : 0) \
+     | (fp_is_enabled (TRP_UNDERFLOW)   ? FE_UNDERFLOW : 0) \
+     | (fp_is_enabled (TRP_INEXACT)     ? FE_INEXACT   : 0))
+
+#endif
diff --git a/lib/fenv-round.c b/lib/fenv-round.c
new file mode 100644 (file)
index 0000000..14048a5
--- /dev/null
@@ -0,0 +1,572 @@
+/* Functions for controlling the floating-point rounding direction.
+   Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+   This file 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.
+
+   This file 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 this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Based on glibc/sysdeps/<cpu>/{fegetround.c,fesetround.c}
+   together with glibc/sysdeps/<cpu>/{fpu_control.h,fenv_private.h,fenv_libc.h}.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <fenv.h>
+
+#include "fenv-private.h"
+
+#if defined __GNUC__ || defined __clang__ || defined _MSC_VER
+
+# if (defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)
+
+int
+fegetround (void)
+{
+#  ifdef _MSC_VER
+  /* XXX Simplify: access the SSE unit.  */
+  fenv_t env;
+  if (fegetenv (&env) != 0)
+    return FE_TONEAREST;
+  unsigned int fctrl = env._Fe_ctl;
+#  else
+  /* Use the rounding direction from the control word of the 387 unit, the
+     so-called fctrl register.
+     The rounding direction of the SSE unit, in the mxcsr register, is expected
+     to be in sync with that.  */
+  unsigned short fctrl;
+  _FPU_GETCW (fctrl);
+#  endif
+#  ifdef _MSC_VER
+  /* The MSVC header files have different values for the rounding directions
+     than all the other platforms.  Map
+       0x0000 -> 0x0000 = FE_TONEAREST
+       0x0400 -> 0x0200 = FE_DOWNWARD
+       0x0800 -> 0x0100 = FE_UPWARD
+       0x0C00 -> 0x0300 = FE_TOWARDZERO  */
+  return ((fctrl & 0x0400) >> 1) | ((fctrl & 0x0800) >> 3);
+#  else
+  return fctrl & 0x0C00;
+#  endif
+}
+
+int
+fesetround (int rounding_direction)
+{
+#  ifdef _MSC_VER
+  /* The MSVC header files have different values for the rounding directions
+     than all the other platforms.  */
+  if ((rounding_direction & ~0x0300) != 0)
+    return -1;
+  /* Map
+     FE_TONEAREST  = 0x0000 -> 0x0000
+     FE_DOWNWARD   = 0x0200 -> 0x0400
+     FE_UPWARD     = 0x0100 -> 0x0800
+     FE_TOWARDZERO = 0x0300 -> 0x0C00  */
+  rounding_direction =
+    ((rounding_direction & 0x0200) << 1) | ((rounding_direction & 0x0100) << 3);
+#  else
+  if ((rounding_direction & ~0x0C00) != 0)
+    return -1;
+#  endif
+
+  /* Set it in the 387 unit.  */
+#  ifdef _MSC_VER
+  /* XXX Simplify: only access the SSE unit.  */
+  fenv_t env;
+  unsigned long orig_ctl;
+  if (fegetenv (&env) != 0)
+    return -1;
+  orig_ctl = env._Fe_ctl;
+  env._Fe_ctl = (env._Fe_ctl & ~0x0C00) | rounding_direction;
+  if (env._Fe_ctl != orig_ctl)
+    {
+      if (fesetenv (&env) != 0)
+        return -1;
+    }
+#  else
+  unsigned short fctrl, orig_fctrl;
+  _FPU_GETCW (orig_fctrl);
+  fctrl = (orig_fctrl & ~0x0C00) | rounding_direction;
+  if (fctrl != orig_fctrl)
+    _FPU_SETCW (fctrl);
+#  endif
+
+  if (CPU_HAS_SSE ())
+    {
+      /* Set it in the SSE unit as well.  */
+      unsigned int mxcsr, orig_mxcsr;
+      _FPU_GETSSECW (orig_mxcsr);
+      mxcsr = (orig_mxcsr & ~(0x0C00 << 3)) | (rounding_direction << 3);
+      if (mxcsr != orig_mxcsr)
+        _FPU_SETSSECW (mxcsr);
+    }
+
+  return 0;
+}
+
+# elif defined __aarch64__ /* arm64 */
+
+int
+fegetround (void)
+{
+  unsigned long fpcr;
+  _FPU_GETCW (fpcr);
+  return (fpcr & 0x00C00000UL)
+#  if FE_TOWARDZERO == 3 /* FreeBSD compatible FE_* values */
+         >> 22
+#  endif
+         ;
+}
+
+int
+fesetround (int rounding_direction)
+{
+#  if FE_TOWARDZERO == 3 /* FreeBSD compatible FE_* values */
+  if ((rounding_direction & ~3) != 0)
+    return -1;
+  rounding_direction = rounding_direction << 22;
+#  else /* glibc compatible FE_* values */
+  if ((rounding_direction & ~0x00C00000UL) != 0)
+    return -1;
+#  endif
+  unsigned long fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = (orig_fpcr & ~0x00C00000UL) | rounding_direction;
+  if (fpcr != orig_fpcr)
+    _FPU_SETCW (fpcr);
+  return 0;
+}
+
+# elif defined __arm__
+
+int
+fegetround (void)
+{
+#  ifdef __SOFTFP__
+  return FE_TONEAREST;
+#  else
+  unsigned int fpscr;
+  _FPU_GETCW (fpscr);
+  return fpscr & 0x00C00000U;
+#  endif
+}
+
+int
+fesetround (int rounding_direction)
+{
+#  ifdef __SOFTFP__
+  if (rounding_direction != FE_TONEAREST)
+    return -1;
+#  else
+  if ((rounding_direction & ~0x00C00000U) != 0)
+    return -1;
+  unsigned int fpscr, orig_fpscr;
+  _FPU_GETCW (orig_fpscr);
+  fpscr = (orig_fpscr & ~0x00C00000U) | rounding_direction;
+  if (fpscr != orig_fpscr)
+    _FPU_SETCW (fpscr);
+#  endif
+  return 0;
+}
+
+# elif defined __alpha
+
+int
+fegetround (void)
+{
+  unsigned long fpcr;
+  _FPU_GETCW (fpcr);
+  return (fpcr >> 58) & 0x3UL;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x3UL) != 0)
+    return -1;
+  unsigned long fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = (orig_fpcr & ~(0x3UL << 58))
+         | ((unsigned long) rounding_direction << 58);
+  if (fpcr != orig_fpcr)
+    _FPU_SETCW (fpcr);
+  return 0;
+}
+
+# elif defined __hppa
+
+int
+fegetround (void)
+{
+  unsigned int fpstatus;
+  _FPU_GETCW (fpstatus);
+  return fpstatus & 0x00000600U;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x00000600U) != 0)
+    return -1;
+  unsigned int fpstatus, orig_fpstatus;
+  _FPU_GETCW (orig_fpstatus);
+  fpstatus = (orig_fpstatus & ~0x00000600U) | rounding_direction;
+  if (fpstatus != orig_fpstatus)
+    _FPU_SETCW (fpstatus);
+  return 0;
+}
+
+# elif defined __ia64__
+
+int
+fegetround (void)
+{
+  unsigned long fpsr;
+  _FPU_GETCW (fpsr);
+  return (fpsr >> 10) & 0x3UL;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x3UL) != 0)
+    return -1;
+  unsigned long fpsr, orig_fpsr;
+  _FPU_GETCW (orig_fpsr);
+  fpsr = (orig_fpsr & ~(0x3UL << 10))
+         | ((unsigned long) rounding_direction << 10);
+  if (fpsr != orig_fpsr)
+    _FPU_SETCW (fpsr);
+  return 0;
+}
+
+# elif defined __m68k__
+
+int
+fegetround (void)
+{
+  unsigned int fpcr;
+  _FPU_GETCW (fpcr);
+  return fpcr & 0x30U;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x30U) != 0)
+    return -1;
+  unsigned int fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = (orig_fpcr & ~0x30U) | rounding_direction;
+  if (fpcr != orig_fpcr)
+    _FPU_SETCW (fpcr);
+  return 0;
+}
+
+# elif defined __mips__
+
+int
+fegetround (void)
+{
+  unsigned int fcsr;
+  _FPU_GETCW (fcsr);
+  return fcsr & 0x3U;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x3U) != 0)
+    return -1;
+  unsigned int fcsr, orig_fcsr;
+  _FPU_GETCW (orig_fcsr);
+  fcsr = (orig_fcsr & ~0x3U) | rounding_direction;
+  if (fcsr != orig_fcsr)
+    _FPU_SETCW (fcsr);
+  return 0;
+}
+
+# elif defined __loongarch__
+
+int
+fegetround (void)
+{
+  unsigned int fcsr;
+  _FPU_GETCW (fcsr);
+  return fcsr & 0x300U;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x300U) != 0)
+    return -1;
+  unsigned int fcsr, orig_fcsr;
+  _FPU_GETCW (orig_fcsr);
+  fcsr = (orig_fcsr & ~0x300U) | rounding_direction;
+  if (fcsr != orig_fcsr)
+    _FPU_SETCW (fcsr);
+  return 0;
+}
+
+# elif defined __powerpc__
+
+/* The AIX header files have different values for the rounding directions
+   than all the other platforms: The values 0 and 1 are swapped.
+   (They probably did this in order to have a trivial FLT_ROUNDS macro, cf.
+   <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/float.h.html>.)
+   Define some handy macros for conversion.  */
+#  ifdef _AIX
+#   define fe_to_hardware(x) ((x) ^ ((x) < 2))
+#   define hardware_to_fe(x) ((x) ^ ((x) < 2))
+#  else
+#   define fe_to_hardware(x) (x)
+#   define hardware_to_fe(x) (x)
+#  endif
+
+int
+fegetround (void)
+{
+#  if 1
+  unsigned int result;
+  __asm__ __volatile__ ("mcrfs 7,7 ; mfcr %0" : "=r" (result) : : "cr7");
+  return hardware_to_fe (result & 3);
+#  else
+  union { unsigned long long u; double f; } memenv;
+  _FPU_GETCW_AS_DOUBLE (memenv.f);
+  return hardware_to_fe (memenv.u & 3);
+#  endif
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x3U) != 0)
+    return -1;
+#  ifdef _AIX
+  rounding_direction = fe_to_hardware (rounding_direction);
+#  endif
+  if (rounding_direction & 2)
+    __asm__ __volatile__ ("mtfsb1 30");
+  else
+    __asm__ __volatile__ ("mtfsb0 30");
+  if (rounding_direction & 1)
+    __asm__ __volatile__ ("mtfsb1 31");
+  else
+    __asm__ __volatile__ ("mtfsb0 31");
+  return 0;
+}
+
+# elif defined __riscv
+
+int
+fegetround (void)
+{
+  int rounding_direction;
+  __asm__ __volatile__ ("frrm %0" : "=r" (rounding_direction));
+#  if FE_UPWARD == 0x60 /* FreeBSD compatible FE_* values */
+  return rounding_direction << 5;
+#  else
+  return rounding_direction;
+#  endif
+}
+
+int
+fesetround (int rounding_direction)
+{
+#  if FE_UPWARD == 0x60 /* FreeBSD compatible FE_* values */
+  if ((rounding_direction & ~0x60) != 0)
+    return -1;
+  rounding_direction = rounding_direction >> 5;
+#  else
+  if ((rounding_direction & ~3) != 0)
+    return -1;
+#  endif
+  __asm__ __volatile__ ("fsrm %z0" : : "rJ" (rounding_direction));
+  return 0;
+}
+
+# elif defined __s390__ || defined __s390x__
+
+int
+fegetround (void)
+{
+  unsigned int fpc;
+  _FPU_GETCW (fpc);
+  return fpc & 0x3U;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x3U) != 0)
+    return -1;
+#  if 1
+  __asm__ __volatile__ ("srnm 0(%0)" : : "a" (rounding_direction));
+#  else
+  unsigned int fpc, orig_fpc;
+  _FPU_GETCW (orig_fpc);
+  fpc = (orig_fpc & ~0x3U) | rounding_direction;
+  if (fpc != orig_fpc)
+    _FPU_SETCW (fpc);
+#  endif
+  return 0;
+}
+
+# elif defined __sh__
+
+int
+fegetround (void)
+{
+  unsigned int fpscr;
+  _FPU_GETCW (fpscr);
+  return fpscr & 0x1U;
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if ((rounding_direction & ~0x1U) != 0)
+    return -1;
+  unsigned int fpscr, orig_fpscr;
+  _FPU_GETCW (orig_fpscr);
+  fpscr = (orig_fpscr & ~0x1U) | rounding_direction;
+  if (fpscr != orig_fpscr)
+    _FPU_SETCW (fpscr);
+  return 0;
+}
+
+# elif defined __sparc
+
+int
+fegetround (void)
+{
+  unsigned long fsr;
+  _FPU_GETCW (fsr);
+  return (fsr & 0xC0000000UL)
+#  if FE_DOWNWARD == 3 /* FreeBSD compatible FE_* values */
+         >> 30
+#  endif
+         ;
+}
+
+int
+fesetround (int rounding_direction)
+{
+#  if FE_DOWNWARD == 3 /* FreeBSD compatible FE_* values */
+  if ((rounding_direction & ~3) != 0)
+    return -1;
+  rounding_direction = (unsigned int) rounding_direction << 30;
+#  else /* glibc compatible FE_* values */
+  if (((unsigned int) rounding_direction & ~0xC0000000UL) != 0)
+    return -1;
+#  endif
+  unsigned long fsr, orig_fsr;
+  _FPU_GETCW (orig_fsr);
+  fsr = (orig_fsr & ~0xC0000000UL) | (unsigned int) rounding_direction;
+  if (fsr != orig_fsr)
+    _FPU_SETCW (fsr);
+  return 0;
+}
+
+# else
+
+#  if defined __GNUC__ || defined __clang__
+#   warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
+#  endif
+#  define NEED_FALLBACK 1
+
+# endif
+
+#else
+
+/* The compiler does not support __asm__ statements or equivalent
+   intrinsics.  */
+
+# if HAVE_FPSETROUND
+/* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2.  */
+
+/* Get fpgetround, fpsetround.  */
+#  include <ieeefp.h>
+
+int
+fegetround (void)
+{
+  return fpgetround ();
+}
+
+int
+fesetround (int rounding_direction)
+{
+  fpsetround (rounding_direction);
+  return 0;
+}
+
+# elif defined _AIX /* AIX */
+
+/* Get fp_read_rnd, fp_swap_rnd.  */
+#  include <float.h>
+
+/* Documentation:
+   <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-read-rnd-fp-swap-rnd-subroutine>  */
+
+int
+fegetround (void)
+{
+  return fp_read_rnd ();
+}
+
+int
+fesetround (int rounding_direction)
+{
+  fp_swap_rnd (rounding_direction);
+  return 0;
+}
+
+# else
+
+#  define NEED_FALLBACK 1
+
+# endif
+
+#endif
+
+#if NEED_FALLBACK
+
+/* A dummy fallback.  */
+
+# include <float.h>
+# include <stdlib.h>
+
+int
+fegetround (void)
+{
+  /* Cf. <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/float.h.html> */
+  switch (FLT_ROUNDS)
+    {
+    case 0: return FE_TOWARDZERO;
+    case 1: return FE_TONEAREST;
+    case 2: return FE_UPWARD;
+    case 3: return FE_DOWNWARD;
+    default: abort ();
+    }
+}
+
+int
+fesetround (int rounding_direction)
+{
+  if (rounding_direction != fegetround ())
+    return -1;
+  return 0;
+}
+
+#endif
index c52d0e0ccb4ca73fa97e5e929a8868993f484f7c..2c70e343ebbadf6cc63f7b6a561041c0028ac9d1 100644 (file)
@@ -37,6 +37,8 @@
  #error "Please include config.h first."
 #endif
 
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
+
 /* The definition of _GL_WARN_ON_USE is copied here.  */
 
 
@@ -180,6 +182,7 @@ typedef unsigned long fenv_t;
 
 # elif defined __aarch64__ /* arm64 */
 
+/* Attention: FreeBSD libc has these values shifted right by 22 bits!  */
 #  define FE_TONEAREST   (0 << 22)
 #  define FE_UPWARD      (1 << 22)
 #  define FE_DOWNWARD    (2 << 22)
@@ -246,6 +249,7 @@ typedef unsigned long fenv_t;
 
 # elif defined __riscv
 
+/* Attention: FreeBSD libc has these values shifted left by 5 bits!  */
 #  define FE_TONEAREST   0
 #  define FE_TOWARDZERO  1
 #  define FE_DOWNWARD    2
@@ -284,6 +288,44 @@ typedef unsigned long fenv_t;
 
 #endif
 
+#if @GNULIB_FEGETROUND@
+/* Returns the current rounding direction.  */
+# if @REPLACE_FEGETROUND@ || (!@HAVE_FEGETROUND@ && (defined __GLIBC__ || defined __FreeBSD__)) /* has an inline definition */
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fegetround
+#   define fegetround rpl_fegetround
+#  endif
+_GL_FUNCDECL_RPL (fegetround, int, (void));
+_GL_CXXALIAS_RPL (fegetround, int, (void));
+# else
+#  if !@HAVE_FEGETROUND@
+_GL_FUNCDECL_SYS (fegetround, int, (void));
+#  endif
+_GL_CXXALIAS_SYS (fegetround, int, (void));
+# endif
+_GL_CXXALIASWARN (fegetround);
+#endif
+
+#if @GNULIB_FESETROUND@
+/* Sets the rounding direction of the current thread.
+   Returns zero if the argument is valid and the operation was thus successful.
+   Returns non-zero upon failure.  */
+# if @REPLACE_FESETROUND@ || (!@HAVE_FESETROUND@ && defined __FreeBSD__) /* has an inline definition */
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fesetround
+#   define fesetround rpl_fesetround
+#  endif
+_GL_FUNCDECL_RPL (fesetround, int, (int rounding_direction));
+_GL_CXXALIAS_RPL (fesetround, int, (int rounding_direction));
+# else
+#  if !@HAVE_FESETROUND@
+_GL_FUNCDECL_SYS (fesetround, int, (int rounding_direction));
+#  endif
+_GL_CXXALIAS_SYS (fesetround, int, (int rounding_direction));
+# endif
+_GL_CXXALIASWARN (fesetround);
+#endif
+
 
 /* ISO C 99 § 7.6.2 Floating-point exceptions
    ISO C 23 § 7.6.4 Floating-point exceptions
diff --git a/m4/fenv-rounding.m4 b/m4/fenv-rounding.m4
new file mode 100644 (file)
index 0000000..f52937c
--- /dev/null
@@ -0,0 +1,77 @@
+# fenv-rounding.m4 serial 1
+dnl Copyright (C) 2023 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FENV_ROUNDING],
+[
+  AC_REQUIRE([gl_FENV_H_DEFAULTS])
+
+  dnl On FreeBSD 11/i386, fesetround needs -lm while fegetround doesn't.
+  gl_MATHFUNC([fesetround], [int], [(int)], [#include <fenv.h>])
+  if test $gl_cv_func_fesetround_no_libm = yes \
+     || test $gl_cv_func_fesetround_in_libm = yes; then
+    dnl The fesetround function does not work on MSVC 14.
+    AC_CACHE_CHECK([whether fesetround works],
+      [gl_cv_func_fesetround_works],
+      [case "$host_os" in
+         # Guess no on native Windows other than mingw.
+         mingw* | windows*)
+           AC_EGREP_CPP([Problem], [
+#ifndef __MINGW32__
+ Problem
+#endif
+             ],
+             [gl_cv_func_fesetround_works="guessing no"],
+             [gl_cv_func_fesetround_works="guessing yes"])
+           ;;
+         *) gl_cv_func_fesetround_works="guessing yes" ;;
+       esac
+      ])
+    case "$gl_cv_func_fesetround_works" in
+      *yes) ;;
+      *) REPLACE_FESETROUND=1 ;;
+    esac
+    if test $REPLACE_FESETROUND = 1; then
+      dnl One more function is defined in the same compilation unit.
+      REPLACE_FEGETROUND=1
+      FENV_ROUNDING_LIBM=
+    else
+      dnl It needs linking with -lm on
+      dnl glibc, FreeBSD, NetBSD, OpenBSD, AIX, HP-UX, IRIX, Solaris, Android.
+      if test $gl_cv_func_fesetround_no_libm = yes; then
+        FENV_ROUNDING_LIBM=
+      else
+        FENV_ROUNDING_LIBM=-lm
+      fi
+    fi
+  else
+    HAVE_FEGETROUND=0
+    HAVE_FESETROUND=0
+    FENV_ROUNDING_LIBM=
+  fi
+  if test $HAVE_FESETROUND = 0 || test $REPLACE_FESETROUND = 1; then
+    gl_PREREQ_FENV_ROUNDING
+    dnl Possibly need -lm for fpgetround(), fpsetround().
+    if test $gl_cv_func_fpsetround_no_libm = no \
+       && test $gl_cv_func_fpsetround_in_libm = yes \
+       && test -z "$FENV_ROUNDING_LIBM"; then
+      FENV_ROUNDING_LIBM=-lm
+    fi
+  fi
+  AC_SUBST([FENV_ROUNDING_LIBM])
+])
+
+dnl Prerequisites of lib/fenv-round.c.
+AC_DEFUN([gl_PREREQ_FENV_ROUNDING],
+[
+  gl_MATHFUNC([fpsetround], [fp_rnd], [(fp_rnd)],
+    [#include <ieeefp.h>
+    ])
+  if test $gl_cv_func_fpsetround_no_libm = yes \
+     || test $gl_cv_func_fpsetround_in_libm = yes; then
+    AC_DEFINE([HAVE_FPSETROUND], [1],
+      [Define to 1 if you have the 'fpsetround' function.])
+  fi
+])
index 5146e580c062fe96aa2f4d034c24d9a056a8429e..f220cea8aca3024a44f7f077afdf67330e5b4bde 100644 (file)
@@ -1,4 +1,4 @@
-# mathfunc.m4 serial 14
+# mathfunc.m4 serial 15
 dnl Copyright (C) 2010-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -40,12 +40,14 @@ AC_DEFUN([gl_MATHFUNC],
                                           [m4_bpatsubst(
                                              [m4_bpatsubst(
                                                 [m4_bpatsubst(
-                                                   [$3],
-                                                   [int\( const\)? \*],
-                                                   [&i_ret])],
-                                                [float\( const\)? \*], [&f_ret])],
-                                             [double\( const\)? \*], [&d_ret])],
-                                          [long double\( const\)? \*], [&l_ret])],
+                                                   [m4_bpatsubst(
+                                                      [$3],
+                                                      [int\( const\)? \*],
+                                                      [&i_ret])],
+                                                   [float\( const\)? \*], [&f_ret])],
+                                                [double\( const\)? \*], [&d_ret])],
+                                             [long double\( const\)? \*], [&l_ret])],
+                                          [fp_rnd], [1])],
                                        [fp_except_t], [1])],
                                     [int], [2])],
                                  [float], [1.618034f])],
index 270db4bd27c80171e7175387dd3da36bfd2cda00..87a9a02d2862fc91a8a64277d74396a81841219c 100644 (file)
@@ -9,6 +9,7 @@ m4/fenv_h.m4
 Depends-on:
 gen-header
 include_next
+snippet/c++defs
 snippet/warn-on-use
 
 configure.ac:
@@ -20,7 +21,7 @@ Makefile.am:
 BUILT_SOURCES += fenv.h
 
 # We need the following in order to create an override of <fenv.h>.
-fenv.h: fenv.in.h $(top_builddir)/config.status $(WARN_ON_USE_H)
+fenv.h: fenv.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H)
 @NMD@  $(AM_V_GEN)$(MKDIR_P) '%reldir%'
        $(gl_V_at)$(SED_HEADER_STDOUT) \
              -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \
@@ -72,6 +73,7 @@ fenv.h: fenv.in.h $(top_builddir)/config.status $(WARN_ON_USE_H)
              -e 's|@''REPLACE_FESETEXCEPTFLAG''@|$(REPLACE_FESETEXCEPTFLAG)|g' \
              -e 's|@''REPLACE_FESETROUND''@|$(REPLACE_FESETROUND)|g' \
              -e 's|@''REPLACE_FETESTEXCEPT''@|$(REPLACE_FETESTEXCEPT)|g' \
+             -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
              -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
              $(srcdir)/fenv.in.h > $@-t
        $(AM_V_at)mv $@-t $@
diff --git a/modules/fenv-rounding b/modules/fenv-rounding
new file mode 100644 (file)
index 0000000..bd7eb48
--- /dev/null
@@ -0,0 +1,36 @@
+Description:
+Functions for controlling the floating-point rounding direction:
+fegetround, fesetround.
+
+Files:
+lib/fenv-round.c
+lib/fenv-private.h
+m4/fenv-rounding.m4
+m4/mathfunc.m4
+
+Depends-on:
+fenv
+
+configure.ac:
+gl_FENV_ROUNDING
+gl_CONDITIONAL([GL_COND_OBJ_FENV_ROUNDING],
+               [test $HAVE_FESETROUND = 0 || test $REPLACE_FESETROUND = 1])
+gl_FENV_MODULE_INDICATOR([fegetround])
+gl_FENV_MODULE_INDICATOR([fesetround])
+
+Makefile.am:
+if GL_COND_OBJ_FENV_ROUNDING
+lib_SOURCES += fenv-round.c
+endif
+
+Include:
+#include <fenv.h>
+
+Link:
+$(FENV_ROUNDING_LIBM)
+
+License:
+LGPLv2+
+
+Maintainer:
+all