This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[gfortran,patch] FPE options, once again
- From: FX Coudert <fxcoudert at gmail dot com>
- To: patch <gcc-patches at gcc dot gnu dot org>, gfortran <fortran at gcc dot gnu dot org>
- Date: Thu, 01 Sep 2005 22:46:33 +0200
- Subject: [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;