This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [gfortran,patch] FPE options, once again
- From: FX Coudert <fxcoudert at gmail dot com>
- To: Paul Brook <paul at codesourcery dot com>
- Cc: fortran at gcc dot gnu dot org, patch <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 26 Sep 2005 21:45:47 +0200
- Subject: Re: [gfortran,patch] FPE options, once again
- References: <431768A9.9050409@gmail.com> <200509081750.12480.paul@codesourcery.com>
:ADDPATCH fortran:
After some time, here is the new (and hopefully last) version of this
patch. I incorporated all of your remarks (see below).
Built and regtested on i686-linux. OK for mainline?
I thought the last time this was discussed (for a different option), the
conclusion was that environment variables were more trouble that they were
worth. Applications are liable to mysteriously break because a user didn't
have the exact same combination of magic environment variables set.
I removed that code.
My preference is for a commandline switch (like you implemented), and maybe a
new intrinsic procedure so an application can control the setting at runtime.
Well, if people ask for it, we'll see, but I'm very uncomfortable with
providing source-code extensions like that.
I agree with RTHs comment that there's no point having all there as separate
variables. We convert to/from a bitmap anyway, so we may as well just use
that bitmap all the time. Also make the bitmasks into #defines so we don't
have hardcoded values in multiple places.
Done.
2005-09-26 Francois-Xavier Coudert <coudert@clipper.ens.fr>
* gfortran.h: Add bitmasks for different FPE traps. Add fpe
member to options_t.
* invoke.texi: Document the new -ffpe-trap option.
* lang.opt: Add -ffpe-trap option.
* options.c (gfc_init_options): Initialize the FPE option.
(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-26 Francois-Xavier Coudert <coudert@clipper.ens.fr>
* Makefile.am: Add fpu.c to the build process, and
target-dependent code as fpu-target.h.
* Makefile.in: Regenerate.
* configure.ac: Add call to configure.host to set
FPU_HOST_HEADER.
* configure: Regenerate.
* configure.host: New script to determine which host-dependent
code should go in.
* libgfortran.h: Add fpe option, remove previous fpu_ options.
Add bitmasks for different FPE traps. Add prototype for set_fpu.
* runtime/environ.c: Remove environment variables to control
fpu behaviour.
* runtime/fpu.c (set_fpe): New function for the front-end.
* runtime/main.c (init): Set FPU state.
* 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.
Index: gcc/fortran/gfortran.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fortran/gfortran.h,v
retrieving revision 1.87
diff -u -3 -p -r1.87 gfortran.h
--- gcc/fortran/gfortran.h 17 Sep 2005 18:57:59 -0000 1.87
+++ gcc/fortran/gfortran.h 26 Sep 2005 19:25:04 -0000
@@ -103,6 +103,15 @@ mstring;
#define GFC_STD_F95_OBS (1<<1) /* Obsoleted in F95. */
#define GFC_STD_F77 (1<<0) /* Up to and including F77. */
+/* Bitmasks for the various FPE that can be enabled. */
+#define GFC_FPE_INVALID (1<<0)
+#define GFC_FPE_DENORMAL (1<<1)
+#define GFC_FPE_ZERO (1<<2)
+#define GFC_FPE_OVERFLOW (1<<3)
+#define GFC_FPE_UNDERFLOW (1<<4)
+#define GFC_FPE_PRECISION (1<<5)
+
+
/*************************** Enums *****************************/
/* The author remains confused to this day about the convention of
@@ -1453,6 +1462,8 @@ typedef struct
int q_kind;
+ int fpe;
+
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 26 Sep 2005 19:25:05 -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.19
diff -u -3 -p -r1.19 lang.opt
--- gcc/fortran/lang.opt 13 Sep 2005 06:24:18 -0000 1.19
+++ gcc/fortran/lang.opt 26 Sep 2005 19:25:05 -0000
@@ -165,6 +165,10 @@ qkind=
Fortran RejectNegative Joined UInteger
-qkind=<n> Set the kind for a real with the 'q' exponent to 'n'
+ffpe-trap=
+Fortran RejectNegative JoinedOrMissing
+-ffpe-trap=[..] Stop on following floating point exceptions
+
std=f95
Fortran
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.25
diff -u -3 -p -r1.25 options.c
--- gcc/fortran/options.c 13 Sep 2005 06:24:18 -0000 1.25
+++ gcc/fortran/options.c 26 Sep 2005 19:25:05 -0000
@@ -76,6 +76,8 @@ gfc_init_options (unsigned int argc ATTR
gfc_option.q_kind = gfc_default_double_kind;
+ gfc_option.fpe = 0;
+
flag_argument_noalias = 2;
flag_errno_math = 0;
@@ -274,6 +276,41 @@ 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 const int opt_exception[] = { GFC_FPE_INVALID, GFC_FPE_DENORMAL,
+ GFC_FPE_ZERO, GFC_FPE_OVERFLOW,
+ GFC_FPE_UNDERFLOW, GFC_FPE_PRECISION,
+ 0 };
+
+ while (*arg)
+ {
+ while (*arg == ',')
+ arg++;
+ while (arg[pos] && arg[pos] != ',')
+ pos++;
+ result = 0;
+ for (n = 0; exception[n] != NULL; n++)
+ {
+ if (exception[n] && strncmp (exception[n], arg, pos) == 0)
+ {
+ gfc_option.fpe |= opt_exception[n];
+ 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 +473,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.69
diff -u -3 -p -r1.69 trans-decl.c
--- gcc/fortran/trans-decl.c 9 Sep 2005 06:00:25 -0000 1.69
+++ gcc/fortran/trans-decl.c 26 Sep 2005 19:25:05 -0000
@@ -85,6 +85,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;
@@ -1876,6 +1877,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);
@@ -1960,6 +1962,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,
@@ -2397,6 +2403,21 @@ 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 != 0)
+ {
+ tree arglist, gfc_c_int_type_node;
+
+ 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,
+ gfc_option.fpe));
+ 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.35
diff -u -3 -p -r1.35 trans.h
--- gcc/fortran/trans.h 9 Sep 2005 06:34:07 -0000 1.35
+++ gcc/fortran/trans.h 26 Sep 2005 19:25:05 -0000
@@ -455,6 +455,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: libgfortran/Makefile.am
===================================================================
RCS file: /cvs/gcc/gcc/libgfortran/Makefile.am,v
retrieving revision 1.42
diff -u -3 -p -r1.42 Makefile.am
--- libgfortran/Makefile.am 25 Sep 2005 21:39:55 -0000 1.42
+++ libgfortran/Makefile.am 26 Sep 2005 19:25:05 -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
# Machine generated specifics
gfor_built_specific_src= \
@@ -393,6 +392,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.34
diff -u -3 -p -r1.34 configure.ac
--- libgfortran/configure.ac 25 Sep 2005 21:39:57 -0000 1.34
+++ libgfortran/configure.ac 26 Sep 2005 19:25:06 -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])
@@ -328,6 +328,17 @@ AC_CHECK_LIB([m],[ynl],[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)
+
# The standard autoconf HAVE_STRUCT_TIMEZONE doesn't actually check
# for struct timezone, as you might think. We also need to check how
# to call gettimeofday if we have it.
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 26 Sep 2005 19:25:06 -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.33
diff -u -3 -p -r1.33 libgfortran.h
--- libgfortran/libgfortran.h 25 Sep 2005 21:39:57 -0000 1.33
+++ libgfortran/libgfortran.h 26 Sep 2005 19:25:06 -0000
@@ -288,8 +288,7 @@ typedef struct
int mem_check;
int use_stderr, all_unbuffered, default_recl;
- int fpu_round, fpu_precision, fpu_invalid, fpu_denormal, fpu_zerodiv,
- fpu_overflow, fpu_underflow, fpu_precision_loss;
+ int fpu_round, fpu_precision, fpe;
int sighup, sigint;
}
@@ -361,6 +360,14 @@ error_codes;
#define GFC_STD_F95_OBS (1<<1) /* Obsoleted in F95. */
#define GFC_STD_F77 (1<<0) /* Up to and including F77. */
+/* Bitmasks for the various FPE that can be enabled.
+ Keep them in sync with their counterparts in gcc/fortran/gfortran.h. */
+#define GFC_FPE_INVALID (1<<0)
+#define GFC_FPE_DENORMAL (1<<1)
+#define GFC_FPE_ZERO (1<<2)
+#define GFC_FPE_OVERFLOW (1<<3)
+#define GFC_FPE_UNDERFLOW (1<<4)
+#define GFC_FPE_PRECISION (1<<5)
/* The filename and line number don't go inside the globals structure.
They are set by the rest of the program and must be linked to. */
@@ -431,6 +438,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/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 26 Sep 2005 19:25:06 -0000
@@ -532,30 +532,6 @@ 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,
- show_boolean,
- "Raise a floating point exception on invalid FP operation.", 0},
-
- {"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,
- "Raise a floating point exception when dividing by zero.", 0},
-
- {"GFORTRAN_FPU_OVERFLOW", 0, &options.fpu_overflow, init_boolean,
- show_boolean,
- "Raise a floating point exception on overflow.", 0},
-
- {"GFORTRAN_FPU_UNDERFLOW", 0, &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,
- show_boolean,
- "Raise a floating point exception on precision loss.", 0},
-
{NULL, 0, NULL, NULL, NULL, NULL, 0}
};
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 26 Sep 2005 19:25:06 -0000
@@ -0,0 +1,16 @@
+#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)
+{
+ options.fpe = exceptions;
+ set_fpu ();
+}
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 26 Sep 2005 19:25:06 -0000
@@ -96,6 +96,7 @@ init (void)
init_variables ();
init_units ();
+ set_fpu ();
init_compile_options ();
#ifdef DEBUG