Hi everyone,
This patch adds FPU support for powerpc on platforms that do not have
glibc. It is basically the same code as glibc has. The motivation for
this was that right now there is no fpu-target.h that works for
powerpc-*-vxworks.
Again, 90% of this code comes directly from glibc. But on vxworks
targets there is no glibc.
I also patched the configure.host script in order to add this in.
Any opinions?
Robert Mason
>From f9449738730fa0d460a30affa826a157bf97cf62 Mon Sep 17 00:00:00 2001
From: rbmj <r...@verizon.net>
Date: Mon, 21 May 2012 15:56:06 -0400
Subject: [PATCH 3/6] Add FPU Support for PPC on VxWorks
libgfortran/config/fpu-ppc.h:
Started work on a fpu-target.h that will work for VxWorks on PPC.
90% of it is stolen from glibc. I just took the necessary pieces
and added the right VxWorks glue. I made as few changes to the
glibc code as possible in order to avoid introducing a bug.
The VxWorks part seems to be correct, but I don't have a whole
lot of experience in this area and documentation is incomplete.
libgfortran/configure.host:
This just adds fpu-ppc.h to the list of targets. For some
reason, my powerpc-wrs-vxworks is getting mis-identified as
AIX, even though it does not have the functions, so I'll also
have to work on a patch for configure.ac. I'll check on that.
Also, I put it before glibc so that glibc targets will get
to use glibc and not rely on my cruft.
---
libgfortran/config/fpu-ppc.h | 407 ++++++++++++++++++++++++++++++++++++++++++
libgfortran/configure.host | 11 ++
2 files changed, 418 insertions(+), 0 deletions(-)
create mode 100644 libgfortran/config/fpu-ppc.h
diff --git a/libgfortran/config/fpu-ppc.h b/libgfortran/config/fpu-ppc.h
new file mode 100644
index 0000000..f27df7f
--- /dev/null
+++ b/libgfortran/config/fpu-ppc.h
@@ -0,0 +1,407 @@
+/* FPU-related code for systems without glibc on powerpc.
+ Copyright (C) 1997, 1998, 1999, 2008 Free Software Foundation, Inc.
+
+This file is part of the GNU Fortran runtime library (libgfortran).
+This file incorporates code from the GNU C Library (glibc) under the GNU LGPL.
+
+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 3 of the License, or (at your option) any later version.
+
+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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+<http://www.gnu.org/licenses/>. */
+
+/* FPU Types/Constants: */
+
+/* Type representing exception flags. */
+typedef unsigned int fexcept_t;
+
+/* Type representing floating-point environment. We leave it as 'double'
+ for efficiency reasons (rather than writing it to a 32-bit integer). */
+typedef double fenv_t;
+
+/* We want to specify the bit pattern of the __fe_*_env constants, so
+ pretend they're really `long long' instead of `double'. */
+
+/* If the default argument is used we use this value. */
+const unsigned long long __fe_dfl_env __attribute__ ((aligned (8))) =
+0xfff8000000000000ULL;
+#define FE_DFL_ENV ((double*)(&__fe_dfl_env))
+
+/* Floating-point environment where all exceptions are enabled. Note that
+ this is not sufficient to give you SIGFPE. */
+const unsigned long long __fe_enabled_env __attribute__ ((aligned (8))) =
+0xfff80000000000f8ULL;
+# define FE_ENABLED_ENV ((double*)(&__fe_enabled_env))
+
+/* Floating-point environment with (processor-dependent) non-IEEE floating
+ point. */
+const unsigned long long __fe_nonieee_env __attribute__ ((aligned (8))) =
+0xfff8000000000004ULL;
+# define FE_NONIEEE_ENV ((double*)(&__fe_nonieee_env))
+
+/* Provide __fe_mask_env and __fe_nomask_env */
+#ifdef __VXWORKS__
+
+/* These are based loosly off of glibc
+
+ see also glibc/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/fe{,no}mask.c
+ */
+
+#include <arch/ppc/vxPpcLib.h>
+#include <arch/ppc/archPpc.h>
+
+#if !defined (_PPC_MSR_FE0) || !defined (_PPC_MSR_FE1)
+#error FPU Support does not appear to exist on target platform
+#else
+
+const fenv_t *
+__fe_nomask_env(void)
+{
+ UINT32 msr = vxMsrGet();
+ msr |= _PPC_MSR_FE0 | _PPC_MSR_FE1;
+ vxMsrSet(msr);
+ return FE_ENABLED_ENV;
+}
+
+const fenv_t *
+__fe_nomask_env(void)
+{
+ UINT32 msr = vxMsrGet();
+ msr &= ~(_PPC_MSR_FE0 | _PPC_MSR_FE1);
+ vxMsrSet(msr);
+ return FE_DFL_ENV;
+}
+
+#endif
+
+#else
+
+/* VxWorks is the only OS that this header supports so far. It would be trivial
+ to also support Linux on PowerPC, but this should be unnecessary as Linux
+ uses glibc so fpu-glibc.h should be used instead anyway. */
+
+/* These stubs won't work... error unless there's reason not to do so: */
+#error Unsupported target, use fpu-glibc.h or similar instead.
+
+#include <errno.h>
+
+/* This is a generic stub. An OS specific override is required to set
+ the FE0/FE1 bits in the MSR. MSR update is privileged, so this will
+ normally involve a syscall. */
+
+const fenv_t *
+__fe_nomask_env(void)
+{
+ __set_errno (ENOSYS);
+ return FE_ENABLED_ENV;
+}
+
+/* This is a generic stub. An OS specific override is required to clear
+ the FE0/FE1 bits in the MSR. MSR update is privileged, so this will
+ normally involve a syscall. */
+
+const fenv_t *
+__fe_mask_env(void)
+{
+ __set_errno (ENOSYS);
+ return FE_DFL_ENV;
+}
+#endif
+
+/* Define bits representing the exception. We use the bit positions of
+ the appropriate bits in the FPSCR... */
+enum
+ {
+ FE_INEXACT = 1 << (31 - 6),
+#define FE_INEXACT FE_INEXACT
+ FE_DIVBYZERO = 1 << (31 - 5),
+#define FE_DIVBYZERO FE_DIVBYZERO
+ FE_UNDERFLOW = 1 << (31 - 4),
+#define FE_UNDERFLOW FE_UNDERFLOW
+ FE_OVERFLOW = 1 << (31 - 3),
+#define FE_OVERFLOW FE_OVERFLOW
+
+ /* ... except for FE_INVALID, for which we use bit 31. FE_INVALID
+ actually corresponds to bits 7 through 12 and 21 through 23
+ in the FPSCR, but we can't use that because the current draft
+ says that it must be a power of 2. Instead we use bit 2 which
+ is the summary bit for all the FE_INVALID exceptions, which
+ kind of makes sense. */
+ FE_INVALID = 1 << (31 - 2),
+#define FE_INVALID FE_INVALID
+
+ /* Breakdown of the FE_INVALID bits. Setting FE_INVALID on an
+ input to a routine is equivalent to setting all of these bits;
+ FE_INVALID will be set on output from a routine iff one of
+ these bits is set. Note, though, that you can't disable or
+ enable these exceptions individually. */
+
+ /* Operation with SNaN. */
+ FE_INVALID_SNAN = 1 << (31 - 7),
+# define FE_INVALID_SNAN FE_INVALID_SNAN
+
+ /* Inf - Inf */
+ FE_INVALID_ISI = 1 << (31 - 8),
+# define FE_INVALID_ISI FE_INVALID_ISI
+
+ /* Inf / Inf */
+ FE_INVALID_IDI = 1 << (31 - 9),
+# define FE_INVALID_IDI FE_INVALID_IDI
+
+ /* 0 / 0 */
+ FE_INVALID_ZDZ = 1 << (31 - 10),
+# define FE_INVALID_ZDZ FE_INVALID_ZDZ
+
+ /* Inf * 0 */
+ FE_INVALID_IMZ = 1 << (31 - 11),
+# define FE_INVALID_IMZ FE_INVALID_IMZ
+
+ /* Comparison with NaN or SNaN. */
+ FE_INVALID_COMPARE = 1 << (31 - 12),
+# define FE_INVALID_COMPARE FE_INVALID_COMPARE
+
+ /* Invalid operation flag for software (not set by hardware). */
+ /* Note that some chips don't have this implemented, presumably
+ because no-one expected anyone to write software for them %-). */
+ FE_INVALID_SOFTWARE = 1 << (31 - 21),
+# define FE_INVALID_SOFTWARE FE_INVALID_SOFTWARE
+
+ /* Square root of negative number (including -Inf). */
+ /* Note that some chips don't have this implemented. */
+ FE_INVALID_SQRT = 1 << (31 - 22),
+# define FE_INVALID_SQRT FE_INVALID_SQRT
+
+ /* Conversion-to-integer of a NaN or a number too large or too small. */
+ FE_INVALID_INTEGER_CONVERSION = 1 << (31 - 23)
+# define FE_INVALID_INTEGER_CONVERSION FE_INVALID_INTEGER_CONVERSION
+
+# define FE_ALL_INVALID \
+ (FE_INVALID_SNAN | FE_INVALID_ISI | FE_INVALID_IDI | FE_INVALID_ZDZ \
+ | FE_INVALID_IMZ | FE_INVALID_COMPARE | FE_INVALID_SOFTWARE \
+ | FE_INVALID_SQRT | FE_INVALID_INTEGER_CONVERSION)
+ };
+
+#define FE_ALL_EXCEPT \
+ (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
+
+/* PowerPC chips support all of the four defined rounding modes. We
+ use the bit pattern in the FPSCR as the values for the
+ appropriate macros. */
+enum
+ {
+ FE_TONEAREST = 0,
+#define FE_TONEAREST FE_TONEAREST
+ FE_TOWARDZERO = 1,
+#define FE_TOWARDZERO FE_TOWARDZERO
+ FE_UPWARD = 2,
+#define FE_UPWARD FE_UPWARD
+ FE_DOWNWARD = 3
+#define FE_DOWNWARD FE_DOWNWARD
+ };
+
+/* Floating-point environment with all exceptions enabled. Note that
+ just evaluating this value does not change the processor exception mode.
+ Passing this mask to fesetenv will result in a prctl syscall to change
+ the MSR FE0/FE1 bits to "Precise Mode". On some processors this will
+ result in slower floating point execution. This will last until an
+ fenv or exception mask is installed that disables all FP exceptions. */
+# define FE_NOMASK_ENV FE_ENABLED_ENV
+
+/* Floating-point environment with all exceptions disabled. Note that
+ just evaluating this value does not change the processor exception mode.
+ Passing this mask to fesetenv will result in a prctl syscall to change
+ the MSR FE0/FE1 bits to "Ignore Exceptions Mode". On most processors
+ this allows the fastest possible floating point execution.*/
+# define FE_MASK_ENV FE_DFL_ENV
+
+/* Type to represent floating point environment */
+
+typedef union
+{
+ fenv_t fenv;
+ unsigned int l[2];
+} fenv_union_t;
+
+/* Set/Get FPSCR Register */
+
+#define fegetenv_register() \
+ ({ fenv_t env; asm volatile ("mffs %0" : "=f" (env)); env; })
+
+#define fesetenv_register(env) \
+ do { \
+ double d = (env); \
+ if(GLRO(dl_hwcap) & PPC_FEATURE_HAS_DFP) \
+ asm volatile (".machine push; " \
+ ".machine \"power6\"; " \
+ "mtfsf 0xff,%0,1,0; " \
+ ".machine pop" : : "f" (d)); \
+ else \
+ asm volatile ("mtfsf 0xff,%0" : : "f" (d)); \
+ } while(0)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+__fegetexcept (void)
+{
+ fenv_union_t fe;
+ int result = 0;
+
+ fe.fenv = fegetenv_register ();
+
+ if (fe.l[1] & (1 << (31 - FPSCR_XE)))
+ result |= FE_INEXACT;
+ if (fe.l[1] & (1 << (31 - FPSCR_ZE)))
+ result |= FE_DIVBYZERO;
+ if (fe.l[1] & (1 << (31 - FPSCR_UE)))
+ result |= FE_UNDERFLOW;
+ if (fe.l[1] & (1 << (31 - FPSCR_OE)))
+ result |= FE_OVERFLOW;
+ if (fe.l[1] & (1 << (31 - FPSCR_VE)))
+ result |= FE_INVALID;
+
+ return result;
+}
+
+int
+feenableexcept (int excepts)
+{
+ fenv_union_t fe;
+ int result, new;
+
+ result = __fegetexcept ();
+
+ if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
+ excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
+
+ fe.fenv = fegetenv_register ();
+ if (excepts & FE_INEXACT)
+ fe.l[1] |= (1 << (31 - FPSCR_XE));
+ if (excepts & FE_DIVBYZERO)
+ fe.l[1] |= (1 << (31 - FPSCR_ZE));
+ if (excepts & FE_UNDERFLOW)
+ fe.l[1] |= (1 << (31 - FPSCR_UE));
+ if (excepts & FE_OVERFLOW)
+ fe.l[1] |= (1 << (31 - FPSCR_OE));
+ if (excepts & FE_INVALID)
+ fe.l[1] |= (1 << (31 - FPSCR_VE));
+ fesetenv_register (fe.fenv);
+
+ new = __fegetexcept ();
+ if (new != 0 && result == 0)
+ (void)__fe_nomask_env ();
+
+ if ((new & excepts) != excepts)
+ result = -1;
+
+ return result;
+}
+
+int
+fedisableexcept (int excepts)
+{
+ fenv_union_t fe;
+ int result, new;
+
+ result = __fegetexcept ();
+
+ if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
+ excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
+
+ fe.fenv = fegetenv_register ();
+ if (excepts & FE_INEXACT)
+ fe.l[1] &= ~(1 << (31 - FPSCR_XE));
+ if (excepts & FE_DIVBYZERO)
+ fe.l[1] &= ~(1 << (31 - FPSCR_ZE));
+ if (excepts & FE_UNDERFLOW)
+ fe.l[1] &= ~(1 << (31 - FPSCR_UE));
+ if (excepts & FE_OVERFLOW)
+ fe.l[1] &= ~(1 << (31 - FPSCR_OE));
+ if (excepts & FE_INVALID)
+ fe.l[1] &= ~(1 << (31 - FPSCR_VE));
+ fesetenv_register (fe.fenv);
+
+ new = __fegetexcept ();
+ if (new == 0 && result != 0)
+ (void)__fe_mask_env ();
+
+ if ((new & excepts) != 0)
+ result = -1;
+ return result;
+}
+
+/* This is from fpu-glibc.h: This is what *all of the above* is for */
+
+void set_fpu (void)
+{
+ if (FE_ALL_EXCEPT != 0)
+ fedisableexcept (FE_ALL_EXCEPT);
+
+ if (options.fpe & GFC_FPE_INVALID)
+#ifdef FE_INVALID
+ feenableexcept (FE_INVALID);
+#else
+ estr_write ("Fortran runtime warning: IEEE 'invalid operation' "
+ "exception not supported.\n");
+#endif
+
+/* glibc does never have a FE_DENORMAL. */
+ if (options.fpe & GFC_FPE_DENORMAL)
+#ifdef FE_DENORMAL
+ feenableexcept (FE_DENORMAL);
+#else
+ estr_write ("Fortran runtime warning: Floating point 'denormal operand' "
+ "exception not supported.\n");
+#endif
+
+ if (options.fpe & GFC_FPE_ZERO)
+#ifdef FE_DIVBYZERO
+ feenableexcept (FE_DIVBYZERO);
+#else
+ estr_write ("Fortran runtime warning: IEEE 'division by zero' "
+ "exception not supported.\n");
+#endif
+
+ if (options.fpe & GFC_FPE_OVERFLOW)
+#ifdef FE_OVERFLOW
+ feenableexcept (FE_OVERFLOW);
+#else
+ estr_write ("Fortran runtime warning: IEEE 'overflow' "
+ "exception not supported.\n");
+#endif
+
+ if (options.fpe & GFC_FPE_UNDERFLOW)
+#ifdef FE_UNDERFLOW
+ feenableexcept (FE_UNDERFLOW);
+#else
+ estr_write ("Fortran runtime warning: IEEE 'underflow' "
+ "exception not supported.\n");
+#endif
+
+ if (options.fpe & GFC_FPE_INEXACT)
+#ifdef FE_INEXACT
+ feenableexcept (FE_INEXACT);
+#else
+ estr_write ("Fortran runtime warning: IEEE 'inexact' "
+ "exception not supported.\n");
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libgfortran/configure.host b/libgfortran/configure.host
index 92b6433..5e4af03 100644
--- a/libgfortran/configure.host
+++ b/libgfortran/configure.host
@@ -20,6 +20,17 @@
# DEFAULTS
fpu_host='fpu-generic'
+# powerpc asm fpu_host based off of glibc for systems without glibc
+# this is before the glibc test so that fpu-glibc will override it, as
+# it requires a *small* amount of OS support (which is only implemented
+# right now with VxWorks), and since it is based off of glibc in theory
+# glibc will always be better/more current/more optimized.
+
+case "${host_cpu}" in
+ powerpc)
+ fpu_host='fpu-ppc' ;;
+esac
+
if test "x${have_feenableexcept}" = "xyes"; then
fpu_host='fpu-glibc'
fi
--
1.7.5.4