]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libgfortran.h (support_fpu_underflow_control, [...]): New prototypes.
authorFrancois-Xavier Coudert <fxcoudert@gcc.gnu.org>
Wed, 9 Jul 2014 20:32:12 +0000 (20:32 +0000)
committerFrançois-Xavier Coudert <fxcoudert@gcc.gnu.org>
Wed, 9 Jul 2014 20:32:12 +0000 (20:32 +0000)
* libgfortran.h (support_fpu_underflow_control,
        get_fpu_underflow_mode, set_fpu_underflow_mode): New prototypes.
* config/fpu-*.h (support_fpu_underflow_control,
get_fpu_underflow_mode, set_fpu_underflow_mode):
New functions.
* ieee/ieee_arithmetic.F90: Support underflow control.

* gfortran.dg/ieee/underflow_1.f90: New file.

From-SVN: r212407

gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/ieee/underflow_1.f90 [new file with mode: 0644]
libgfortran/ChangeLog
libgfortran/config/fpu-387.h
libgfortran/config/fpu-aix.h
libgfortran/config/fpu-generic.h
libgfortran/config/fpu-glibc.h
libgfortran/config/fpu-sysv.h
libgfortran/ieee/ieee_arithmetic.F90
libgfortran/libgfortran.h

index b2e6a0168b89c0f2243bc51865603a8da30f2ade..e4cd3bc637471e5de81e9b8433a86721fcd2b75c 100644 (file)
@@ -1,3 +1,7 @@
+2014-07-09  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
+
+       * gfortran.dg/ieee/underflow_1.f90: New file.
+
 2014-07-09  Richard Biener  <rguenther@suse.de>
 
        PR c-family/61741
diff --git a/gcc/testsuite/gfortran.dg/ieee/underflow_1.f90 b/gcc/testsuite/gfortran.dg/ieee/underflow_1.f90
new file mode 100644 (file)
index 0000000..b77a90c
--- /dev/null
@@ -0,0 +1,50 @@
+! { dg-do run }
+! { dg-require-effective-target sse2_runtime { target { i?86-*-* x86_64-*-* } } }
+! { dg-additional-options "-msse2 -mfpmath=sse" { target { i?86-*-* x86_64-*-* } } }
+
+program test_underflow_control
+  use ieee_arithmetic
+  use iso_fortran_env
+
+  logical l
+  real, volatile :: x
+  double precision, volatile :: y
+  integer, parameter :: kx = kind(x), ky = kind(y)
+
+  if (ieee_support_underflow_control(x)) then
+
+    x = tiny(x)
+    call ieee_set_underflow_mode(.true.)
+    x = x / 2000._kx
+    if (x == 0) call abort
+    call ieee_get_underflow_mode(l)
+    if (.not. l) call abort
+
+    x = tiny(x)
+    call ieee_set_underflow_mode(.false.)
+    x = x / 2000._kx
+    if (x > 0) call abort
+    call ieee_get_underflow_mode(l)
+    if (l) call abort
+
+  end if
+
+  if (ieee_support_underflow_control(y)) then
+
+    y = tiny(y)
+    call ieee_set_underflow_mode(.true.)
+    y = y / 2000._ky
+    if (y == 0) call abort
+    call ieee_get_underflow_mode(l)
+    if (.not. l) call abort
+
+    y = tiny(y)
+    call ieee_set_underflow_mode(.false.)
+    y = y / 2000._ky
+    if (y > 0) call abort
+    call ieee_get_underflow_mode(l)
+    if (l) call abort
+
+  end if
+
+end program
index e57f34e711da0ad37aaf5fe356437e845b21e817..245e6dbed5b9038217421f3a1f2d1a6469cef715 100644 (file)
@@ -1,3 +1,12 @@
+2014-07-09  Francois-Xavier Coudert  <fxcoudert@gcc.gnu.org>
+
+       * libgfortran.h (support_fpu_underflow_control,
+       get_fpu_underflow_mode, set_fpu_underflow_mode): New prototypes.
+       * config/fpu-*.h (support_fpu_underflow_control,
+       get_fpu_underflow_mode, set_fpu_underflow_mode):
+       New functions.
+       * ieee/ieee_arithmetic.F90: Support underflow control.
+
 2014-07-08  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * config/fpu-sysv.h (get_fpu_rounding_mode): Use FP_RN, FP_RP,
index 2c5a5fcc6fa71af8f52ffda5de5141c9e1ef90d2..201173e581316bdfde2f55777a9733cc5f388552 100644 (file)
@@ -62,6 +62,11 @@ has_sse (void)
 
 #define _FPU_RC_MASK    0x3
 
+/* Enable flush to zero mode.  */
+
+#define MXCSR_FTZ (1 << 15)
+
+
 /* This structure corresponds to the layout of the block
    written by FSTENV.  */
 typedef struct
@@ -82,7 +87,6 @@ typedef struct
 }
 my_fenv_t;
 
-
 /* Check we can actually store the FPU state in the allocated size.  */
 _Static_assert (sizeof(my_fenv_t) <= (size_t) GFC_FPE_STATE_BUFFER_SIZE,
                "GFC_FPE_STATE_BUFFER_SIZE is too small");
@@ -455,3 +459,47 @@ set_fpu_state (void *state)
     __asm__ __volatile__ ("%vldmxcsr\t%0" : : "m" (envp->__mxcsr));
 }
 
+
+int
+support_fpu_underflow_control (int kind)
+{
+  if (!has_sse())
+    return 0;
+
+  return (kind == 4 || kind == 8) ? 1 : 0;
+}
+
+
+int
+get_fpu_underflow_mode (void)
+{
+  unsigned int cw_sse;
+
+  if (!has_sse())
+    return 1;
+
+  __asm__ __volatile__ ("%vstmxcsr\t%0" : "=m" (cw_sse));
+
+  /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow.  */
+  return (cw_sse & MXCSR_FTZ) ? 0 : 1;
+}
+
+
+void
+set_fpu_underflow_mode (int gradual)
+{
+  unsigned int cw_sse;
+
+  if (!has_sse())
+    return;
+
+  __asm__ __volatile__ ("%vstmxcsr\t%0" : "=m" (cw_sse));
+
+  if (gradual)
+    cw_sse &= ~MXCSR_FTZ;
+  else
+    cw_sse |= MXCSR_FTZ;
+
+  __asm__ __volatile__ ("%vldmxcsr\t%0" : : "m" (cw_sse));
+}
+
index c2970452bc13e05801489a584c398b549149b527..aec7756fda506a411dc4bf6ecf11c6b4871c5c9f 100644 (file)
@@ -417,3 +417,23 @@ set_fpu_state (void *state)
   fesetenv (state);
 }
 
+
+int
+support_fpu_underflow_control (int kind __attribute__((unused)))
+{
+  return 0;
+}
+
+
+int
+get_fpu_underflow_mode (void)
+{
+  return 0;
+}
+
+
+void
+set_fpu_underflow_mode (int gradual __attribute__((unused)))
+{
+}
+
index bbad875f40ef670206b59e53c55d2d744cd3a8e6..e739cd7bc26730a9717211e6a8af208f851cc12f 100644 (file)
@@ -75,3 +75,24 @@ void
 set_fpu_rounding_mode (int round __attribute__((unused)))
 {
 }
+
+
+int
+support_fpu_underflow_control (int kind __attribute__((unused)))
+{
+  return 0;
+}
+
+
+int
+get_fpu_underflow_mode (void)
+{
+  return 0;
+}
+
+
+void
+set_fpu_underflow_mode (int gradual __attribute__((unused)))
+{
+}
+
index b6ea1203a6264eccbf348631939e6c58889213fb..149e8a3ac92681ea24116afadfef6b6dfdbbd2f2 100644 (file)
@@ -429,3 +429,53 @@ set_fpu_state (void *state)
   fesetenv (state);
 }
 
+
+/* Underflow in glibc is currently only supported on alpha, through
+   the FE_MAP_UMZ macro and __ieee_set_fp_control() function call.  */
+
+int
+support_fpu_underflow_control (int kind __attribute__((unused)))
+{
+#if defined(__alpha__) && defined(FE_MAP_UMZ)
+  return (kind == 4 || kind == 8) ? 1 : 0;
+#else
+  return 0;
+#endif
+}
+
+
+int
+get_fpu_underflow_mode (void)
+{
+#if defined(__alpha__) && defined(FE_MAP_UMZ)
+
+  fenv_t state = __ieee_get_fp_control ();
+
+  /* Return 0 for abrupt underflow (flush to zero), 1 for gradual underflow.  */
+  return (state & FE_MAP_UMZ) ? 0 : 1;
+
+#else
+
+  return 0;
+
+#endif
+}
+
+
+void
+set_fpu_underflow_mode (int gradual __attribute__((unused)))
+{
+#if defined(__alpha__) && defined(FE_MAP_UMZ)
+
+  fenv_t state = __ieee_get_fp_control ();
+
+  if (gradual)
+    state &= ~FE_MAP_UMZ;
+  else
+    state |= FE_MAP_UMZ;
+
+  __ieee_set_fp_control (state);
+
+#endif
+}
+
index 559e3f34348166931d923b4a2d506aac5c689267..225f591af720ded7d56691fe750905d9fae7b8ef 100644 (file)
@@ -425,3 +425,23 @@ set_fpu_state (void *s)
   fpsetround (state->round);
 }
 
+
+int
+support_fpu_underflow_control (int kind __attribute__((unused)))
+{
+  return 0;
+}
+
+
+int
+get_fpu_underflow_mode (void)
+{
+  return 0;
+}
+
+
+void
+set_fpu_underflow_mode (int gradual __attribute__((unused)))
+{
+}
+
index 1dce4f79ee4e3dcb34863242ded2e6d7c1021fab..22ff55b9a80f286cd2a74b93bc59c35ef537fd74 100644 (file)
@@ -349,6 +349,29 @@ module IEEE_ARITHMETIC
     end function
   end interface
 
+  ! IEEE_SUPPORT_UNDERFLOW_CONTROL
+
+  interface IEEE_SUPPORT_UNDERFLOW_CONTROL
+    module procedure IEEE_SUPPORT_UNDERFLOW_CONTROL_4, &
+                     IEEE_SUPPORT_UNDERFLOW_CONTROL_8, &
+#ifdef HAVE_GFC_REAL_10
+                     IEEE_SUPPORT_UNDERFLOW_CONTROL_10, &
+#endif
+#ifdef HAVE_GFC_REAL_16
+                     IEEE_SUPPORT_UNDERFLOW_CONTROL_16, &
+#endif
+                     IEEE_SUPPORT_UNDERFLOW_CONTROL_NOARG
+  end interface
+  public :: IEEE_SUPPORT_UNDERFLOW_CONTROL
+  
+  ! Interface to the FPU-specific function
+  interface
+    pure integer function support_underflow_control_helper(kind) &
+        bind(c, name="_gfortrani_support_fpu_underflow_control")
+      integer, intent(in), value :: kind
+    end function
+  end interface
+
 ! IEEE_SUPPORT_* generic functions
 
 #if defined(HAVE_GFC_REAL_10) && defined(HAVE_GFC_REAL_16)
@@ -373,7 +396,6 @@ SUPPORTGENERIC(IEEE_SUPPORT_IO)
 SUPPORTGENERIC(IEEE_SUPPORT_NAN)
 SUPPORTGENERIC(IEEE_SUPPORT_SQRT)
 SUPPORTGENERIC(IEEE_SUPPORT_STANDARD)
-SUPPORTGENERIC(IEEE_SUPPORT_UNDERFLOW_CONTROL)
 
 contains
 
@@ -560,7 +582,6 @@ contains
   subroutine IEEE_GET_ROUNDING_MODE (ROUND_VALUE)
     implicit none
     type(IEEE_ROUND_TYPE), intent(out) :: ROUND_VALUE
-    integer :: i
 
     interface
       integer function helper() &
@@ -568,9 +589,7 @@ contains
       end function
     end interface
 
-    ! FIXME: Use intermediate variable i to avoid triggering PR59023
-    i = helper()
-    ROUND_VALUE = IEEE_ROUND_TYPE(i)
+    ROUND_VALUE = IEEE_ROUND_TYPE(helper())
   end subroutine
 
 
@@ -596,10 +615,14 @@ contains
   subroutine IEEE_GET_UNDERFLOW_MODE (GRADUAL)
     implicit none
     logical, intent(out) :: GRADUAL
-    ! We do not support getting/setting underflow mode yet. We still
-    ! provide the procedures to avoid link-time error if a user program
-    ! uses it protected by a call to IEEE_SUPPORT_UNDERFLOW_CONTROL
-    call abort
+
+    interface
+      integer function helper() &
+        bind(c, name="_gfortrani_get_fpu_underflow_mode")
+      end function
+    end interface
+
+    GRADUAL = (helper() /= 0)
   end subroutine
 
 
@@ -608,10 +631,15 @@ contains
   subroutine IEEE_SET_UNDERFLOW_MODE (GRADUAL)
     implicit none
     logical, intent(in) :: GRADUAL
-    ! We do not support getting/setting underflow mode yet. We still
-    ! provide the procedures to avoid link-time error if a user program
-    ! uses it protected by a call to IEEE_SUPPORT_UNDERFLOW_CONTROL
-    call abort
+
+    interface
+      subroutine helper(val) &
+          bind(c, name="_gfortrani_set_fpu_underflow_mode")
+        integer, value :: val
+      end subroutine
+    end interface
+
+    call helper(merge(1, 0, GRADUAL))
   end subroutine
 
 ! IEEE_SUPPORT_ROUNDING
@@ -658,6 +686,46 @@ contains
 #endif
   end function
 
+! IEEE_SUPPORT_UNDERFLOW_CONTROL
+
+  pure logical function IEEE_SUPPORT_UNDERFLOW_CONTROL_4 (X) result(res)
+    implicit none
+    real(kind=4), intent(in) :: X
+    res = (support_underflow_control_helper(4) /= 0)
+  end function
+
+  pure logical function IEEE_SUPPORT_UNDERFLOW_CONTROL_8 (X) result(res)
+    implicit none
+    real(kind=8), intent(in) :: X
+    res = (support_underflow_control_helper(8) /= 0)
+  end function
+
+#ifdef HAVE_GFC_REAL_10
+  pure logical function IEEE_SUPPORT_UNDERFLOW_CONTROL_10 (X) result(res)
+    implicit none
+    real(kind=10), intent(in) :: X
+    res = .false.
+  end function
+#endif
+
+#ifdef HAVE_GFC_REAL_16
+  pure logical function IEEE_SUPPORT_UNDERFLOW_CONTROL_16 (X) result(res)
+    implicit none
+    real(kind=16), intent(in) :: X
+    res = .false.
+  end function
+#endif
+
+  pure logical function IEEE_SUPPORT_UNDERFLOW_CONTROL_NOARG () result(res)
+    implicit none
+#if defined(HAVE_GFC_REAL_10) || defined(HAVE_GFC_REAL_16)
+    res = .false.
+#else
+    res = (support_underflow_control_helper(4) /= 0 &
+           .and. support_underflow_control_helper(8) /= 0)
+#endif
+  end function
+
 ! IEEE_SUPPORT_* functions
 
 #define SUPPORTMACRO(NAME, INTKIND, VALUE) \
@@ -801,17 +869,4 @@ SUPPORTMACRO_NOARG(IEEE_SUPPORT_STANDARD,.false.)
 SUPPORTMACRO_NOARG(IEEE_SUPPORT_STANDARD,.true.)
 #endif
 
-! IEEE_SUPPORT_UNDERFLOW_CONTROL
-
-SUPPORTMACRO(IEEE_SUPPORT_UNDERFLOW_CONTROL,4,.false.)
-SUPPORTMACRO(IEEE_SUPPORT_UNDERFLOW_CONTROL,8,.false.)
-#ifdef HAVE_GFC_REAL_10
-SUPPORTMACRO(IEEE_SUPPORT_UNDERFLOW_CONTROL,10,.false.)
-#endif
-#ifdef HAVE_GFC_REAL_16
-SUPPORTMACRO(IEEE_SUPPORT_UNDERFLOW_CONTROL,16,.false.)
-#endif
-SUPPORTMACRO_NOARG(IEEE_SUPPORT_UNDERFLOW_CONTROL,.false.)
-
-
 end module IEEE_ARITHMETIC
index dbc3f29cd60b27985c18ac2b4a170fc394672192..d2de76fcb92730528730caa8e0a5ae06642ed15c 100644 (file)
@@ -775,6 +775,15 @@ internal_proto(get_fpu_state);
 extern void set_fpu_state (void *);
 internal_proto(set_fpu_state);
 
+extern int get_fpu_underflow_mode (void);
+internal_proto(get_fpu_underflow_mode);
+
+extern void set_fpu_underflow_mode (int);
+internal_proto(set_fpu_underflow_mode);
+
+extern int support_fpu_underflow_control (int);
+internal_proto(support_fpu_underflow_control);
+
 /* memory.c */
 
 extern void *xmalloc (size_t) __attribute__ ((malloc));