This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gfortran,patch] FPE options, once again


This is the new version of the FPE patch for gfortran, using glibc-specific code on systems where it is available, and runtime detection of SSE units.

I think the code itself is now in pretty good shape, although i'm a bit worried of having heard no word from other gfortran developpers about things such as the option name and the need/convenience of having environment variables.

Regtested on i686-linux. Testing in progress on i686-freebsd, x86_64-linux and i386-openbsd (no glibc, no SSE).

OK for mainline? Do we want this on 4.0?

FX
2005-09-01  Francois-Xavier Coudert  <coudert@clipper.ens.fr>

	* lang.opt: Add -ffpe-trap optiond.
	* invoke.texi: Document the new -ffpe-trap option.
	* gfortran.h (gfc_options_t): Add fields for all possible
	FPE exceptions.
	* options.c (gfc_init_options): Initialize all FPE options.
	(gfc_handle_fpe_trap_option): New function to parse the argument
	of the -ffpe-trap option.
	(gfc_handle_option): Add case for -ffpe-trap.
	* trans-decl.c: Declare a tree for the set_fpe library function.
	(gfc_build_builtin_function_decls): Build this tree.
	(gfc_generate_function_code): Generate a call to set_fpe at
	the beginning of the main program.
	* trans.h: New tree for the set_fpe library function.


2005-09-01  Francois-Xavier Coudert  <coudert@clipper.ens.fr>

	* libgfortran.h: Prototype for set_fpu.
	* runtime/environ.c (variable_table): Default value for
	GFORTRAN_FPU_* options is now -1, which means "not specified",
	and is different from 0, which is "specified to be false" and
	overrides the compile-time options.
	* runtime/fpu.c (set_fpe): New function for the front-end.
	* runtime/main.c (init): Set FPU state.
	* Makefile.am: Add fpu.c to the build process, and
	target-dependent code as fpu-target.h.
	* Makefile.in: Regenerate.
	* aclocal.m4: Regenerate.
	* config: New directory to store host-dependent code.
	* config/fpu-387.h: New file with code handling the i387 FPU.
	* config/fpu-glibc.h: New file with code for glibc systems.
	* config/fpu-generic.h: Fallback for the most generic host. Issue
	warnings.
	* configure: Regenerate.
	* config.h.in: Regenerate.
	* configure.ac: Add call to configure.host to set
	FPU_HOST_HEADER.
	* configure.host: New script to determine which host-dependent
	code should go in.
Index: libgfortran/runtime/fpu.c
===================================================================
RCS file: libgfortran/runtime/fpu.c
diff -N libgfortran/runtime/fpu.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgfortran/runtime/fpu.c	1 Sep 2005 20:38:15 -0000
@@ -0,0 +1,36 @@
+#include "libgfortran.h"
+
+/* We include the platform-dependent code.  */
+#include "fpu-target.h"
+
+
+/* Function called by the front-end to tell us
+   when a FPE should be raised.  */
+extern void set_fpe (int);
+export_proto(set_fpe);
+
+void
+set_fpe (int exceptions)
+{
+  int invalid = exceptions & 0x01;
+  int denormal = exceptions & 0x02;
+  int zero = exceptions & 0x04;
+  int overflow = exceptions & 0x08;
+  int underflow = exceptions & 0x10;
+  int precision = exceptions & 0x20;
+  
+  if (invalid && options.fpu_invalid == -1)
+    options.fpu_invalid = 1;
+  if (denormal && options.fpu_denormal == -1)
+    options.fpu_denormal = 1;
+  if (zero && options.fpu_zerodiv == -1)
+    options.fpu_zerodiv = 1;
+  if (overflow && options.fpu_overflow == -1)
+    options.fpu_overflow = 1;
+  if (underflow && options.fpu_underflow == -1)
+    options.fpu_underflow = 1;
+  if (precision && options.fpu_precision_loss == -1)
+    options.fpu_precision_loss = 1;
+
+  set_fpu ();
+}
Index: libgfortran/Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/Makefile.am,v
retrieving revision 1.41
diff -u -3 -p -r1.41 Makefile.am
--- libgfortran/Makefile.am	11 Aug 2005 13:50:10 -0000	1.41
+++ libgfortran/Makefile.am	1 Sep 2005 20:34:53 -0000
@@ -18,8 +18,6 @@ libgfortranbegin_la_LDFLAGS = -static
 ## use -iquote
 AM_CPPFLAGS = -iquote$(srcdir)/io
 
-libgfortranincludedir = $(includedir)/gforio
-
 gfor_io_src= \
 io/close.c \
 io/file_pos.c \
@@ -97,6 +95,7 @@ gfor_src= \
 runtime/compile_options.c \
 runtime/environ.c \
 runtime/error.c \
+runtime/fpu.c \
 runtime/main.c \
 runtime/memory.c \
 runtime/pause.c \
@@ -300,7 +299,7 @@ gfor_built_src= $(i_all_c) $(i_any_c) $(
     $(i_eoshift3_c) $(i_cshift1_c) $(i_reshape_c) $(in_pack_c) $(in_unpack_c) \
     $(i_exponent_c) $(i_fraction_c) $(i_nearest_c) $(i_set_exponent_c) \
     $(i_pow_c) \
-    selected_int_kind.inc selected_real_kind.inc kinds.h
+    selected_int_kind.inc selected_real_kind.inc kinds.h fpu-target.h
 
 # We only use these if libm doesn't contain complex math functions.
 
@@ -429,6 +428,9 @@ selected_int_kind.inc: $(srcdir)/mk-sik-
 selected_real_kind.inc: $(srcdir)/mk-srk-inc.sh
 	$(SHELL) $(srcdir)/mk-srk-inc.sh '$(FCCOMPILE)' > $@
 
+fpu-target.h: $(srcdir)/$(FPU_HOST_HEADER)
+	cp $(srcdir)/$(FPU_HOST_HEADER) $@
+
 ## A 'normal' build shouldn't need to regenerate these
 ## so we only include them in maintainer mode
 
Index: libgfortran/configure.ac
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/configure.ac,v
retrieving revision 1.31
diff -u -3 -p -r1.31 configure.ac
--- libgfortran/configure.ac	27 Aug 2005 16:01:53 -0000	1.31
+++ libgfortran/configure.ac	1 Sep 2005 20:34:54 -0000
@@ -158,7 +158,7 @@ AC_TYPE_OFF_T
 AC_STDC_HEADERS
 AC_HAVE_HEADERS(stdlib.h stdio.h string.h stddef.h math.h unistd.h signal.h)
 AC_CHECK_HEADERS(time.h sys/params.h sys/time.h sys/times.h sys/resource.h)
-AC_CHECK_HEADERS(sys/mman.h sys/types.h sys/stat.h ieeefp.h)
+AC_CHECK_HEADERS(sys/mman.h sys/types.h sys/stat.h ieeefp.h fenv.h)
 AC_CHECK_HEADER([complex.h],[AC_DEFINE([HAVE_COMPLEX_H], [1], [complex.h exists])])
 
 AC_CHECK_MEMBERS([struct stat.st_blksize])
@@ -233,6 +233,18 @@ AC_CHECK_LIB([m],[ynf],[AC_DEFINE([HAVE_
 # Fallback in case isfinite is not available.
 AC_CHECK_LIB([m],[finite],[AC_DEFINE([HAVE_FINITE],[1],[libm includes finite])])
 
+# Check for GNU libc feenableexcept
+AC_CHECK_LIB([m],[feenableexcept],[have_feenableexcept=yes AC_DEFINE([HAVE_FEENABLEEXCEPT],[1],[libm includes feenableexcept])])
+
+# Runs configure.host to set up necessary host-dependent shell variables.
+# We then display a message about it, and propagate them through the
+# build chain.
+. ${srcdir}/configure.host
+AC_MSG_NOTICE([FPU dependent file will be ${fpu_host}.h])
+FPU_HOST_HEADER=config/${fpu_host}.h
+AC_SUBST(FPU_HOST_HEADER)
+
+
 # Let the user override this
 AC_ARG_ENABLE(cmath,
 	AC_HELP_STRING([--enable-cmath],[Include complex math functions]),
Index: libgfortran/configure.host
===================================================================
RCS file: libgfortran/configure.host
diff -N libgfortran/configure.host
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgfortran/configure.host	1 Sep 2005 20:34:54 -0000
@@ -0,0 +1,32 @@
+# configure.host
+#
+# This shell script handles all host based configuration for libgfortran.
+# It sets various shell variables based on the the host triplet.
+# You can modify this shell script without rerunning autoconf/aclocal/etc.
+# This file is "sourced", not executed.
+#
+#
+# It uses the following shell variables as set by config.guess:
+#   host                The configuration host (full CPU-vendor-OS triplet)
+#   host_cpu            The configuration host CPU
+#   host_os             The configuration host OS
+#
+#
+# It sets the following shell variables:
+#
+#   fpu_host            FPU-specific code file, defaults to fpu-generic.
+
+
+# DEFAULTS
+fpu_host=fpu-generic
+
+# HOST-SPECIFIC OVERRIDES
+case "${host_cpu}" in
+  i?86 | x86_64)
+    fpu_host='fpu-387' ;;
+esac
+
+# CONFIGURATION-SPECIFIC OVERRIDES
+if test "x${have_feenableexcept}" = "xyes"; then
+  fpu_host='fpu-glibc'
+fi
Index: libgfortran/libgfortran.h
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/libgfortran.h,v
retrieving revision 1.30
diff -u -3 -p -r1.30 libgfortran.h
--- libgfortran/libgfortran.h	17 Aug 2005 02:48:35 -0000	1.30
+++ libgfortran/libgfortran.h	1 Sep 2005 20:34:54 -0000
@@ -429,6 +429,11 @@ internal_proto(translate_error);
 extern void generate_error (int, const char *);
 internal_proto(generate_error);
 
+/* fpu.c */
+
+extern void set_fpu (void);
+internal_proto(set_fpu);
+
 /* memory.c */
 
 extern void *get_mem (size_t) __attribute__ ((malloc));
Index: libgfortran/config/fpu-387.h
===================================================================
RCS file: libgfortran/config/fpu-387.h
diff -N libgfortran/config/fpu-387.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgfortran/config/fpu-387.h	1 Sep 2005 20:34:54 -0000
@@ -0,0 +1,103 @@
+/* FPU-related code for x86 and x86_64 processors.
+   Copyright 2005 Free Software Foundation, Inc.
+   Contributed by Francois-Xavier Coudert <coudert@clipper.ens.fr>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Libgfortran 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+
+static int
+has_sse (void)
+{
+#ifdef __x86_64__
+  return 1;
+#else
+  unsigned int eax, ebx, ecx, edx;
+
+  /* See if we can use cpuid.  */
+  asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
+		"pushl %0; popfl; pushfl; popl %0; popfl"
+		: "=&r" (eax), "=&r" (ebx)
+		: "i" (0x00200000));
+
+  if (((eax ^ ebx) & 0x00200000) == 0)
+    return 0;
+
+  /* Check the highest input value for eax.  */
+  asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+		: "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+		: "0" (0));
+
+  if (eax == 0)
+    return 0;
+
+  asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+		: "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+		: "0" (1));
+
+  if (edx & (1 << 25))
+    return 1;
+
+  return 0;
+#endif
+}
+
+void set_fpu (void)
+{
+  short cw;
+  int cw_sse;
+
+  /* i387 -- see linux <fpu_control.h> header file for details.  */
+#define _FPU_MASK_IM  0x01
+#define _FPU_MASK_DM  0x02
+#define _FPU_MASK_ZM  0x04
+#define _FPU_MASK_OM  0x08
+#define _FPU_MASK_UM  0x10
+#define _FPU_MASK_PM  0x20
+  asm volatile ("fnstcw %0" : "=m" (cw));
+  cw |= _FPU_MASK_IM | _FPU_MASK_DM | _FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM | _FPU_MASK_PM;
+  if (options.fpu_invalid == 1) cw &= ~_FPU_MASK_IM;
+  if (options.fpu_denormal == 1) cw &= ~_FPU_MASK_DM;
+  if (options.fpu_zerodiv == 1) cw &= ~_FPU_MASK_ZM;
+  if (options.fpu_overflow == 1) cw &= ~_FPU_MASK_OM;
+  if (options.fpu_underflow == 1) cw &= ~_FPU_MASK_UM;
+  if (options.fpu_precision_loss == 1) cw &= ~_FPU_MASK_PM;
+  asm volatile ("fldcw %0" : : "m" (cw));
+
+  if (has_sse())
+    {
+      /* SSE */
+      asm volatile ("stmxcsr %0" : : "m" (cw_sse));
+      cw_sse &= 0xFFFF0000;
+      if (options.fpu_invalid != 1) cw_sse |= 1 << 7;
+      if (options.fpu_denormal != 1) cw_sse |= 1 << 8;
+      if (options.fpu_zerodiv != 1) cw_sse |= 1 << 9;
+      if (options.fpu_overflow != 1) cw_sse |= 1 << 10;
+      if (options.fpu_underflow != 1) cw_sse |= 1 << 11;
+      if (options.fpu_precision_loss != 1) cw_sse |= 1 << 12;
+      asm volatile ("ldmxcsr %0" : : "m" (cw_sse));
+    }
+}
Index: libgfortran/config/fpu-generic.h
===================================================================
RCS file: libgfortran/config/fpu-generic.h
diff -N libgfortran/config/fpu-generic.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgfortran/config/fpu-generic.h	1 Sep 2005 20:34:54 -0000
@@ -0,0 +1,57 @@
+/* Fallback FPU-related code (for systems not otherwise supported).
+   Copyright 2005 Free Software Foundation, Inc.
+   Contributed by Francois-Xavier Coudert <coudert@clipper.ens.fr>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Libgfortran 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+
+/* Fallback FPU-related code for systems not otherwise supported. This
+   is mainly telling the user that we will not be able to do what he
+   requested.  */
+
+void
+set_fpu (void)
+{
+  if (options.fpu_invalid == 1)
+    st_printf ("Fortran runtime warning: IEEE 'invalid operation' "
+	       "exception not supported.\n");
+  if (options.fpu_denormal == 1)
+    st_printf ("Fortran runtime warning: IEEE 'denormal number' "
+	       "exception not supported.\n");
+  if (options.fpu_zerodiv == 1)
+    st_printf ("Fortran runtime warning: IEEE 'division by zero' "
+	       "exception not supported.\n");
+  if (options.fpu_overflow == 1)
+    st_printf ("Fortran runtime warning: IEEE 'overflow' "
+	       "exception not supported.\n");
+  if (options.fpu_underflow == 1)
+    st_printf ("Fortran runtime warning: IEEE 'underflow' "
+	       "exception not supported.\n");
+  if (options.fpu_precision_loss == 1)
+    st_printf ("Fortran runtime warning: IEEE 'loss of precision' "
+	       "exception not supported.\n");
+}
Index: libgfortran/config/fpu-glibc.h
===================================================================
RCS file: libgfortran/config/fpu-glibc.h
diff -N libgfortran/config/fpu-glibc.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ libgfortran/config/fpu-glibc.h	1 Sep 2005 20:34:54 -0000
@@ -0,0 +1,93 @@
+/* FPU-related code for systems with GNU libc.
+   Copyright 2005 Free Software Foundation, Inc.
+   Contributed by Francois-Xavier Coudert <coudert@clipper.ens.fr>
+
+This file is part of the GNU Fortran 95 runtime library (libgfortran).
+
+Libgfortran is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file into combinations with other programs,
+and to distribute those combinations without any restriction coming
+from the use of this file.  (The General Public License restrictions
+do apply in other respects; for example, they cover modification of
+the file, and distribution when not linked into a combine
+executable.)
+
+Libgfortran 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public
+License along with libgfortran; see the file COPYING.  If not,
+write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+
+/* FPU-related code for systems with the GNU libc, providing the
+   feenableexcept function in fenv.h to set individual exceptions
+   (there's nothing to do that in C99).  */
+
+#define __USE_GNU
+#ifdef HAVE_FENV_H
+#include <fenv.h>
+#endif
+
+void set_fpu (void)
+{
+  fedisableexcept (FE_ALL_EXCEPT);
+
+  if (options.fpu_invalid == 1)
+#ifdef FE_INVALID
+    feenableexcept (FE_INVALID);
+#else
+    st_printf ("Fortran runtime warning: IEEE 'invalid operation' "
+	       "exception not supported.\n");
+#endif
+
+/* glibc does never have a FE_DENORMAL.  */
+  if (options.fpu_denormal == 1)
+#ifdef FE_DENORMAL
+    feenableexcept (FE_DENORMAL);
+#else
+    st_printf ("Fortran runtime warning: IEEE 'denormal number' "
+	       "exception not supported.\n");
+#endif
+
+  if (options.fpu_zerodiv == 1)
+#ifdef FE_DIVBYZERO
+    feenableexcept (FE_DIVBYZERO);
+#else
+    st_printf ("Fortran runtime warning: IEEE 'division by zero' "
+	       "exception not supported.\n");
+#endif
+
+  if (options.fpu_overflow == 1)
+#ifdef FE_OVERFLOW
+    feenableexcept (FE_OVERFLOW);
+#else
+    st_printf ("Fortran runtime warning: IEEE 'overflow' "
+	       "exception not supported.\n");
+#endif
+
+  if (options.fpu_underflow == 1)
+#ifdef FE_UNDERFLOW
+    feenableexcept (FE_UNDERFLOW);
+#else
+    st_printf ("Fortran runtime warning: IEEE 'underflow' "
+	       "exception not supported.\n");
+#endif
+
+  if (options.fpu_precision_loss == 1)
+#ifdef FE_INEXACT
+    feenableexcept (FE_INEXACT);
+#else
+    st_printf ("Fortran runtime warning: IEEE 'loss of precision' "
+	       "exception not supported.\n");
+#endif
+}
Index: libgfortran/runtime/environ.c
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/runtime/environ.c,v
retrieving revision 1.13
diff -u -3 -p -r1.13 environ.c
--- libgfortran/runtime/environ.c	17 Aug 2005 02:49:07 -0000	1.13
+++ libgfortran/runtime/environ.c	1 Sep 2005 20:34:54 -0000
@@ -532,27 +532,27 @@ static variable variable_table[] = {
    show_precision,
    "Precision of intermediate results.  Values are 24, 53 and 64.", 0},
 
-  {"GFORTRAN_FPU_INVALID", 1, &options.fpu_invalid, init_boolean,
+  {"GFORTRAN_FPU_INVALID", -1, &options.fpu_invalid, init_boolean,
    show_boolean,
    "Raise a floating point exception on invalid FP operation.", 0},
 
-  {"GFORTRAN_FPU_DENORMAL", 1, &options.fpu_denormal, init_boolean,
+  {"GFORTRAN_FPU_DENORMAL", -1, &options.fpu_denormal, init_boolean,
    show_boolean,
    "Raise a floating point exception when denormal numbers are encountered.",
    0},
 
-  {"GFORTRAN_FPU_ZERO", 0, &options.fpu_zerodiv, init_boolean, show_boolean,
+  {"GFORTRAN_FPU_ZERO", -1, &options.fpu_zerodiv, init_boolean, show_boolean,
    "Raise a floating point exception when dividing by zero.", 0},
 
-  {"GFORTRAN_FPU_OVERFLOW", 0, &options.fpu_overflow, init_boolean,
+  {"GFORTRAN_FPU_OVERFLOW", -1, &options.fpu_overflow, init_boolean,
    show_boolean,
    "Raise a floating point exception on overflow.", 0},
 
-  {"GFORTRAN_FPU_UNDERFLOW", 0, &options.fpu_underflow, init_boolean,
+  {"GFORTRAN_FPU_UNDERFLOW", -1, &options.fpu_underflow, init_boolean,
    show_boolean,
    "Raise a floating point exception on underflow.", 0},
 
-  {"GFORTRAN_FPU_PRECISION", 0, &options.fpu_precision_loss, init_boolean,
+  {"GFORTRAN_FPU_PRECISION", -1, &options.fpu_precision_loss, init_boolean,
    show_boolean,
    "Raise a floating point exception on precision loss.", 0},
 
Index: libgfortran/runtime/main.c
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/runtime/main.c,v
retrieving revision 1.9
diff -u -3 -p -r1.9 main.c
--- libgfortran/runtime/main.c	17 Aug 2005 02:49:08 -0000	1.9
+++ libgfortran/runtime/main.c	1 Sep 2005 20:34:54 -0000
@@ -96,6 +96,7 @@ init (void)
   init_variables ();
 
   init_units ();
+  set_fpu ();
   init_compile_options ();
 
 #ifdef DEBUG
Index: gcc/fortran/gfortran.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/gfortran.h,v
retrieving revision 1.84
diff -u -3 -p -r1.84 gfortran.h
--- gcc/fortran/gfortran.h	31 Aug 2005 12:31:29 -0000	1.84
+++ gcc/fortran/gfortran.h	1 Sep 2005 20:35:50 -0000
@@ -1444,6 +1444,9 @@ typedef struct
 
   int q_kind;
 
+  int fpe_invalid, fpe_denormal, fpe_zero, fpe_overflow, fpe_underflow,
+      fpe_precision;
+
   int warn_std;
   int allow_std;
   int warn_nonstd_intrinsics;
Index: gcc/fortran/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/invoke.texi,v
retrieving revision 1.21
diff -u -3 -p -r1.21 invoke.texi
--- gcc/fortran/invoke.texi	31 Aug 2005 12:31:30 -0000	1.21
+++ gcc/fortran/invoke.texi	1 Sep 2005 20:35:50 -0000
@@ -133,7 +133,7 @@ by type.  Explanations are in the follow
 @item Debugging Options
 @xref{Debugging Options,,Options for Debugging Your Program or GCC}.
 @gccoptlist{
--fdump-parse-tree}
+-fdump-parse-tree -ffpe-trap=@var{list}}
 
 @item Directory Options
 @xref{Directory Options,,Options for Directory Search}.
@@ -464,6 +464,22 @@ Output the internal parse tree before st
 really useful for debugging gfortran itself.
 @end table
 
+@table @gcctabopt
+@cindex -ffpe-trap=@var{list} option
+@cindex option, -ffpe-trap=@var{list}
+@item -ffpe-trap=@var{list}
+Specify a list of IEEE exceptions when a Floating Point Exception
+(FPE) should be raised.  On most systems, this will result in a SIGFPE
+signal being sent and the program being interrupted, producing a core
+file useful for debugging.  @var{list} is a (possibly empty) comma-separated
+list of the following IEEE exceptions: @samp{invalid} (invalid floating
+point operation, such as @code{sqrt(-1.0)}), @samp{zero} (division by
+zero), @samp{overflow} (overflow in a floating point operation),
+@samp{underflow} (underflow in a floating point operation),
+@samp{precision} (loss of precision during operation) and @samp{denormal}
+(operation produced a denormal denormal value).
+@end table
+
 @xref{Debugging Options,,Options for Debugging Your Program or GCC,
 gcc,Using the GNU Compiler Collection (GCC)}, for more information on
 debugging options.
Index: gcc/fortran/lang.opt
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/lang.opt,v
retrieving revision 1.18
diff -u -3 -p -r1.18 lang.opt
--- gcc/fortran/lang.opt	31 Aug 2005 12:31:30 -0000	1.18
+++ gcc/fortran/lang.opt	1 Sep 2005 20:35:50 -0000
@@ -165,6 +165,10 @@ qkind=
 F95 RejectNegative Joined UInteger
 -qkind=<n>	Set the kind for a real with the 'q' exponent to 'n'
 
+ffpe-trap=
+F95 RejectNegative JoinedOrMissing
+-ffpe-trap=[..]	Stop on following floating point exceptions
+
 std=f95
 F95
 Conform to the ISO Fortran 95 standard
Index: gcc/fortran/options.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/options.c,v
retrieving revision 1.24
diff -u -3 -p -r1.24 options.c
--- gcc/fortran/options.c	31 Aug 2005 12:31:30 -0000	1.24
+++ gcc/fortran/options.c	1 Sep 2005 20:35:50 -0000
@@ -76,6 +76,13 @@ gfc_init_options (unsigned int argc ATTR
 
   gfc_option.q_kind = gfc_default_double_kind;
 
+  gfc_option.fpe_invalid = 0;
+  gfc_option.fpe_denormal = 0;
+  gfc_option.fpe_zero = 0;
+  gfc_option.fpe_overflow = 0;
+  gfc_option.fpe_underflow = 0;
+  gfc_option.fpe_precision = 0;
+
   flag_argument_noalias = 2;
   flag_errno_math = 0;
 
@@ -274,6 +281,43 @@ gfc_handle_module_path_options (const ch
   strcat (gfc_option.module_dir, "/");
 }
 
+static void
+gfc_handle_fpe_trap_option (const char *arg)
+{
+  int result, pos = 0, n;
+  static const char * const exception[] = { "invalid", "denormal", "zero",
+                                            "overflow", "underflow",
+					    "precision", NULL };
+  static int * const opt_exception[] = { &gfc_option.fpe_invalid,
+					 &gfc_option.fpe_denormal,
+					 &gfc_option.fpe_zero,
+					 &gfc_option.fpe_overflow,
+					 &gfc_option.fpe_underflow,
+					 &gfc_option.fpe_precision };
+ 
+  while (*arg)
+    {
+      while (*arg == ',')
+	arg++;
+      while (arg[pos] && arg[pos] != ',')
+	pos++;
+      result = 0;
+      for (n = 0; exception[n] != NULL; n++)
+	{
+	  if (strncmp (exception[n], arg, pos) == 0)
+	    {
+	      *(opt_exception[n]) = 1;
+	      arg += pos;
+	      pos = 0;
+	      result = 1;
+	      break;
+	    }
+	}
+      if (! result)
+	gfc_fatal_error ("Argument to -ffpe-trap is not valid: %s", arg);
+    }
+}
+
 /* Handle command-line options.  Returns 0 if unrecognized, 1 if
    recognized and handled.  */
 int
@@ -436,6 +480,10 @@ gfc_handle_option (size_t scode, const c
       gfc_handle_module_path_options (arg);
       break;
     
+    case OPT_ffpe_trap_:
+      gfc_handle_fpe_trap_option (arg);
+      break;
+
     case OPT_std_f95:
       gfc_option.allow_std = GFC_STD_F95_OBS | GFC_STD_F95 | GFC_STD_F77;
       gfc_option.warn_std = GFC_STD_F95_OBS;
Index: gcc/fortran/trans-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/trans-decl.c,v
retrieving revision 1.67
diff -u -3 -p -r1.67 trans-decl.c
--- gcc/fortran/trans-decl.c	24 Aug 2005 20:04:20 -0000	1.67
+++ gcc/fortran/trans-decl.c	1 Sep 2005 20:35:50 -0000
@@ -83,6 +83,7 @@ tree gfor_fndecl_stop_numeric;
 tree gfor_fndecl_stop_string;
 tree gfor_fndecl_select_string;
 tree gfor_fndecl_runtime_error;
+tree gfor_fndecl_set_fpe;
 tree gfor_fndecl_set_std;
 tree gfor_fndecl_in_pack;
 tree gfor_fndecl_in_unpack;
@@ -1874,6 +1875,7 @@ gfc_build_intrinsic_function_decls (void
 void
 gfc_build_builtin_function_decls (void)
 {
+  tree gfc_c_int_type_node = gfc_get_int_type (gfc_c_int_kind);
   tree gfc_int4_type_node = gfc_get_int_type (4);
   tree gfc_int8_type_node = gfc_get_int_type (8);
   tree gfc_logical4_type_node = gfc_get_logical_type (4);
@@ -1946,6 +1948,10 @@ gfc_build_builtin_function_decls (void)
   /* The runtime_error function does not return.  */
   TREE_THIS_VOLATILE (gfor_fndecl_runtime_error) = 1;
 
+  gfor_fndecl_set_fpe =
+    gfc_build_library_function_decl (get_identifier (PREFIX("set_fpe")),
+				    void_type_node, 1, gfc_c_int_type_node);
+
   gfor_fndecl_set_std =
     gfc_build_library_function_decl (get_identifier (PREFIX("set_std")),
 				    void_type_node,
@@ -2379,6 +2385,33 @@ gfc_generate_function_code (gfc_namespac
       gfc_add_expr_to_block (&body, tmp);
     }
 
+  /* If this is the main program and a -ffpe-trap option was provided,
+     add a call to set_fpe so that the library will raise a FPE when
+     needed.  */
+  if (sym->attr.is_main_program &&
+      (gfc_option.fpe_invalid || gfc_option.fpe_denormal ||
+       gfc_option.fpe_zero || gfc_option.fpe_overflow ||
+       gfc_option.fpe_underflow || gfc_option.fpe_precision))
+    {
+      tree arglist, gfc_c_int_type_node;
+      int exceptions;
+
+      exceptions = (gfc_option.fpe_invalid ? 0x01 : 0)
+	           | (gfc_option.fpe_denormal ? 0x02 : 0)
+	           | (gfc_option.fpe_zero ? 0x04 : 0)
+	           | (gfc_option.fpe_overflow ? 0x08 : 0)
+	           | (gfc_option.fpe_underflow ? 0x10 : 0)
+	           | (gfc_option.fpe_precision ? 0x20 : 0);
+
+      gfc_c_int_type_node = gfc_get_int_type (gfc_c_int_kind);
+      arglist = gfc_chainon_list (NULL_TREE,
+				  build_int_cst (gfc_c_int_type_node,
+						 exceptions));
+
+      tmp = gfc_build_function_call (gfor_fndecl_set_fpe, arglist);
+      gfc_add_expr_to_block (&body, tmp);
+    }
+
   if (TREE_TYPE (DECL_RESULT (fndecl)) != void_type_node
       && sym->attr.subroutine)
     {
Index: gcc/fortran/trans.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/trans.h,v
retrieving revision 1.32
diff -u -3 -p -r1.32 trans.h
--- gcc/fortran/trans.h	11 Aug 2005 13:50:10 -0000	1.32
+++ gcc/fortran/trans.h	1 Sep 2005 20:35:50 -0000
@@ -453,6 +453,7 @@ extern GTY(()) tree gfor_fndecl_stop_num
 extern GTY(()) tree gfor_fndecl_stop_string;
 extern GTY(()) tree gfor_fndecl_select_string;
 extern GTY(()) tree gfor_fndecl_runtime_error;
+extern GTY(()) tree gfor_fndecl_set_fpe;
 extern GTY(()) tree gfor_fndecl_set_std;
 extern GTY(()) tree gfor_fndecl_in_pack;
 extern GTY(()) tree gfor_fndecl_in_unpack;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]