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]

Re: [gfortran,patch] FPE options, once again


: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

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