[v4,08/17] RISC-V: Generic <math.h> and soft-fp Routines

Message ID 20180113103816.4861-9-palmer@dabbelt.com
State New, archived
Headers

Commit Message

Palmer Dabbelt Jan. 13, 2018, 10:38 a.m. UTC
  This patch contains the miscellaneous math routines and headers we have
implemented for RISC-V.  This includes things from <math.h> that aren't
completely ISA-generic, floating-point bit manipulation, and soft-fp
hooks.

FIXME: add ieee745/soft-fp via a riscv/soft-fp directory.
---
 sysdeps/riscv/bits/fenv.h           |  74 ++++++++++++++++++++++++
 sysdeps/riscv/fpu_control.h         |  74 ++++++++++++++++++++++++
 sysdeps/riscv/math-tests.h          |  30 ++++++++++
 sysdeps/riscv/soft-fp/Makefile      |   3 +
 sysdeps/riscv/soft-fp/e_sqrtl.c     |  37 ++++++++++++
 sysdeps/riscv/soft-fp/sfp-machine.h | 112 ++++++++++++++++++++++++++++++++++++
 sysdeps/riscv/tininess.h            |   1 +
 7 files changed, 331 insertions(+)
 create mode 100644 sysdeps/riscv/bits/fenv.h
 create mode 100644 sysdeps/riscv/fpu_control.h
 create mode 100644 sysdeps/riscv/math-tests.h
 create mode 100644 sysdeps/riscv/soft-fp/Makefile
 create mode 100644 sysdeps/riscv/soft-fp/e_sqrtl.c
 create mode 100644 sysdeps/riscv/soft-fp/sfp-machine.h
 create mode 100644 sysdeps/riscv/tininess.h
  

Comments

Joseph Myers Jan. 15, 2018, 4:59 p.m. UTC | #1
On Sat, 13 Jan 2018, Palmer Dabbelt wrote:

> This patch contains the miscellaneous math routines and headers we have
> implemented for RISC-V.  This includes things from <math.h> that aren't
> completely ISA-generic, floating-point bit manipulation, and soft-fp
> hooks.
> 
> FIXME: add ieee745/soft-fp via a riscv/soft-fp directory.

Again, it should be a riscv/nofpu directory, and riscv/soft-fp shouldn't 
exist.

> diff --git a/sysdeps/riscv/math-tests.h b/sysdeps/riscv/math-tests.h

> +#define EXCEPTION_TESTS_float 0
> +#define EXCEPTION_TESTS_double        0
> +#define EXCEPTION_TESTS_long_double   0

I'd expect that to be conditional on soft-float, as exceptions should be 
supported for hard-float (whether the hard-float or soft-float ABI is 
used).  I'd also expect ROUNDING_TESTS_* to be defined to ((MODE) == 
FE_TONEAREST) for soft-float, as on other architectures, given that 
rounding modes are only supported for hard-float.
  
Palmer Dabbelt Jan. 22, 2018, 11:16 p.m. UTC | #2
On Mon, 15 Jan 2018 08:59:06 PST (-0800), joseph@codesourcery.com wrote:
> On Sat, 13 Jan 2018, Palmer Dabbelt wrote:
>
>> This patch contains the miscellaneous math routines and headers we have
>> implemented for RISC-V.  This includes things from <math.h> that aren't
>> completely ISA-generic, floating-point bit manipulation, and soft-fp
>> hooks.
>>
>> FIXME: add ieee745/soft-fp via a riscv/soft-fp directory.
>
> Again, it should be a riscv/nofpu directory, and riscv/soft-fp shouldn't
> exist.

Ya, sorry about that, this should be fixed.

>
>> diff --git a/sysdeps/riscv/math-tests.h b/sysdeps/riscv/math-tests.h
>
>> +#define EXCEPTION_TESTS_float 0
>> +#define EXCEPTION_TESTS_double        0
>> +#define EXCEPTION_TESTS_long_double   0
>
> I'd expect that to be conditional on soft-float, as exceptions should be
> supported for hard-float (whether the hard-float or soft-float ABI is
> used).  I'd also expect ROUNDING_TESTS_* to be defined to ((MODE) ==
> FE_TONEAREST) for soft-float, as on other architectures, given that
> rounding modes are only supported for hard-float.

The RISC-V ISA doesn't support taking traps on floating-point exceptions, just 
polling the flags register.  My understanding was that we should be 
unconditionally setting these flags, but if I'm wrong we'll go through and 
change it.
  
Joseph Myers Jan. 22, 2018, 11:26 p.m. UTC | #3
On Mon, 22 Jan 2018, Palmer Dabbelt wrote:

> > > diff --git a/sysdeps/riscv/math-tests.h b/sysdeps/riscv/math-tests.h
> > 
> > > +#define EXCEPTION_TESTS_float 0
> > > +#define EXCEPTION_TESTS_double        0
> > > +#define EXCEPTION_TESTS_long_double   0
> > 
> > I'd expect that to be conditional on soft-float, as exceptions should be
> > supported for hard-float (whether the hard-float or soft-float ABI is
> > used).  I'd also expect ROUNDING_TESTS_* to be defined to ((MODE) ==
> > FE_TONEAREST) for soft-float, as on other architectures, given that
> > rounding modes are only supported for hard-float.
> 
> The RISC-V ISA doesn't support taking traps on floating-point exceptions, just
> polling the flags register.  My understanding was that we should be
> unconditionally setting these flags, but if I'm wrong we'll go through and
> change it.

EXCEPTION_TESTS_* are not about traps, they're about raising/testing the 
exception flags.  It's EXCEPTION_ENABLE_SUPPORTED that's about trapping on 
floating-point exceptions (along with EXCEPTION_SET_FORCES_TRAP for those 
architectures that support trapping and where explicitly setting an 
exception flag automatically causes a trap).
  
Palmer Dabbelt Jan. 23, 2018, 3:40 a.m. UTC | #4
On Mon, 22 Jan 2018 15:26:25 PST (-0800), joseph@codesourcery.com wrote:
> On Mon, 22 Jan 2018, Palmer Dabbelt wrote:
>
>> > > diff --git a/sysdeps/riscv/math-tests.h b/sysdeps/riscv/math-tests.h
>> >
>> > > +#define EXCEPTION_TESTS_float 0
>> > > +#define EXCEPTION_TESTS_double        0
>> > > +#define EXCEPTION_TESTS_long_double   0
>> >
>> > I'd expect that to be conditional on soft-float, as exceptions should be
>> > supported for hard-float (whether the hard-float or soft-float ABI is
>> > used).  I'd also expect ROUNDING_TESTS_* to be defined to ((MODE) ==
>> > FE_TONEAREST) for soft-float, as on other architectures, given that
>> > rounding modes are only supported for hard-float.
>>
>> The RISC-V ISA doesn't support taking traps on floating-point exceptions, just
>> polling the flags register.  My understanding was that we should be
>> unconditionally setting these flags, but if I'm wrong we'll go through and
>> change it.
>
> EXCEPTION_TESTS_* are not about traps, they're about raising/testing the
> exception flags.  It's EXCEPTION_ENABLE_SUPPORTED that's about trapping on
> floating-point exceptions (along with EXCEPTION_SET_FORCES_TRAP for those
> architectures that support trapping and where explicitly setting an
> exception flag automatically causes a trap).

Thanks, I must have gotten confused.  We'll sort it out.
  

Patch

diff --git a/sysdeps/riscv/bits/fenv.h b/sysdeps/riscv/bits/fenv.h
new file mode 100644
index 000000000000..e23b7e253d93
--- /dev/null
+++ b/sysdeps/riscv/bits/fenv.h
@@ -0,0 +1,74 @@ 
+/* Floating point environment, RISC-V version.
+   Copyright (C) 1998-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _FENV_H
+# error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
+#endif
+
+enum
+  {
+    FE_INEXACT   =
+#define FE_INEXACT	(0x01)
+      FE_INEXACT,
+    FE_UNDERFLOW =
+#define FE_UNDERFLOW	(0x02)
+      FE_UNDERFLOW,
+    FE_OVERFLOW  =
+#define FE_OVERFLOW	(0x04)
+      FE_OVERFLOW,
+    FE_DIVBYZERO =
+#define FE_DIVBYZERO	(0x08)
+      FE_DIVBYZERO,
+    FE_INVALID   =
+#define FE_INVALID	(0x10)
+      FE_INVALID
+  };
+
+#define FE_ALL_EXCEPT \
+	(FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
+
+enum
+  {
+    FE_TONEAREST  =
+#define FE_TONEAREST	(0x0)
+      FE_TONEAREST,
+    FE_TOWARDZERO =
+#define FE_TOWARDZERO	(0x1)
+      FE_TOWARDZERO,
+    FE_DOWNWARD   =
+#define FE_DOWNWARD	(0x2)
+      FE_DOWNWARD,
+    FE_UPWARD     =
+#define FE_UPWARD	(0x3)
+      FE_UPWARD
+  };
+
+
+typedef unsigned int fexcept_t;
+typedef unsigned int fenv_t;
+
+/* If the default argument is used we use this value.  */
+#define FE_DFL_ENV	((__const fenv_t *) -1)
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/riscv/fpu_control.h b/sysdeps/riscv/fpu_control.h
new file mode 100644
index 000000000000..c050d279b246
--- /dev/null
+++ b/sysdeps/riscv/fpu_control.h
@@ -0,0 +1,74 @@ 
+/* FPU control word bits.  RISC-V version.
+   Copyright (C) 1996-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _FPU_CONTROL_H
+#define _FPU_CONTROL_H
+
+#include <features.h>
+
+#ifndef __riscv_flen
+
+# define _FPU_RESERVED 0xffffffff
+# define _FPU_DEFAULT  0x00000000
+typedef unsigned int fpu_control_t;
+# define _FPU_GETCW(cw) (cw) = 0
+# define _FPU_SETCW(cw) do { } while (0)
+extern fpu_control_t __fpu_control;
+
+#else /* __riscv_flen */
+
+# define _FPU_RESERVED 0
+# define _FPU_DEFAULT  0
+# define _FPU_IEEE     _FPU_DEFAULT
+
+/* Type of the control word.  */
+typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
+
+/* Macros for accessing the hardware control word.  */
+# define _FPU_GETCW(cw) __asm__ volatile ("frsr %0" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ volatile ("fssr %z0" : : "rJ" (cw))
+
+/* Default control word set at startup.  */
+extern fpu_control_t __fpu_control;
+
+# define _FCLASS(x) (__extension__ ({ int __res; \
+  if (sizeof (x) * 8 > __riscv_flen) __builtin_trap (); \
+  if (sizeof (x) == 4) asm ("fclass.s %0, %1" : "=r" (__res) : "f" (x)); \
+  else if (sizeof (x) == 8) asm ("fclass.d %0, %1" : "=r" (__res) : "f" (x)); \
+  else __builtin_trap (); \
+  __res; }))
+
+# define _FCLASS_MINF     (1 << 0)
+# define _FCLASS_MNORM    (1 << 1)
+# define _FCLASS_MSUBNORM (1 << 2)
+# define _FCLASS_MZERO    (1 << 3)
+# define _FCLASS_PZERO    (1 << 4)
+# define _FCLASS_PSUBNORM (1 << 5)
+# define _FCLASS_PNORM    (1 << 6)
+# define _FCLASS_PINF     (1 << 7)
+# define _FCLASS_SNAN     (1 << 8)
+# define _FCLASS_QNAN     (1 << 9)
+# define _FCLASS_ZERO     (_FCLASS_MZERO | _FCLASS_PZERO)
+# define _FCLASS_SUBNORM  (_FCLASS_MSUBNORM | _FCLASS_PSUBNORM)
+# define _FCLASS_NORM     (_FCLASS_MNORM | _FCLASS_PNORM)
+# define _FCLASS_INF      (_FCLASS_MINF | _FCLASS_PINF)
+# define _FCLASS_NAN      (_FCLASS_SNAN | _FCLASS_QNAN)
+
+#endif /* __riscv_flen */
+
+#endif	/* fpu_control.h */
diff --git a/sysdeps/riscv/math-tests.h b/sysdeps/riscv/math-tests.h
new file mode 100644
index 000000000000..e7f3c44209a5
--- /dev/null
+++ b/sysdeps/riscv/math-tests.h
@@ -0,0 +1,30 @@ 
+/* Configuration for math tests.  RISC-V version
+   Copyright (C) 2014-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Copied from the aarch64 version
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Trapping exceptions are not supported on RISC-V.  */
+#define EXCEPTION_ENABLE_SUPPORTED(EXCEPT)	((EXCEPT) == 0)
+
+#define EXCEPTION_TESTS_float 0
+#define EXCEPTION_TESTS_double        0
+#define EXCEPTION_TESTS_long_double   0
+
+/* RISC-V floating-point instructions do not preserve NaN payloads.  */
+#define SNAN_TESTS_PRESERVE_PAYLOAD	0
+
+#include_next <math-tests.h>
diff --git a/sysdeps/riscv/soft-fp/Makefile b/sysdeps/riscv/soft-fp/Makefile
new file mode 100644
index 000000000000..ada13e8b70e5
--- /dev/null
+++ b/sysdeps/riscv/soft-fp/Makefile
@@ -0,0 +1,3 @@ 
+ifeq ($(subdir),math)
+CPPFLAGS += -I../soft-fp
+endif
diff --git a/sysdeps/riscv/soft-fp/e_sqrtl.c b/sysdeps/riscv/soft-fp/e_sqrtl.c
new file mode 100644
index 000000000000..9e4209452107
--- /dev/null
+++ b/sysdeps/riscv/soft-fp/e_sqrtl.c
@@ -0,0 +1,37 @@ 
+/* long double square root in software floating-point emulation.
+   Copyright (C) 1997-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <soft-fp.h>
+#include <quad.h>
+
+long double
+__ieee754_sqrtl (const long double a)
+{
+  FP_DECL_EX;
+  FP_DECL_Q (A); FP_DECL_Q (C);
+  long double c;
+
+  FP_INIT_ROUNDMODE;
+  FP_UNPACK_Q (A, a);
+  FP_SQRT_Q (C, A);
+  FP_PACK_Q (c, C);
+  FP_HANDLE_EXCEPTIONS;
+  return c;
+}
+strong_alias (__ieee754_sqrtl, __sqrtl_finite)
diff --git a/sysdeps/riscv/soft-fp/sfp-machine.h b/sysdeps/riscv/soft-fp/sfp-machine.h
new file mode 100644
index 000000000000..b86a9cfa66f4
--- /dev/null
+++ b/sysdeps/riscv/soft-fp/sfp-machine.h
@@ -0,0 +1,112 @@ 
+/* RISC-V softfloat definitions
+   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+#if __riscv_xlen == 32
+
+# define _FP_W_TYPE_SIZE		32
+# define _FP_W_TYPE		unsigned long
+# define _FP_WS_TYPE		signed long
+# define _FP_I_TYPE		long
+
+# define _FP_MUL_MEAT_S(R, X, Y)				\
+  _FP_MUL_MEAT_1_wide (_FP_WFRACBITS_S, R, X, Y, umul_ppmm)
+# define _FP_MUL_MEAT_D(R, X, Y)				\
+  _FP_MUL_MEAT_2_wide (_FP_WFRACBITS_D, R, X, Y, umul_ppmm)
+# define _FP_MUL_MEAT_Q(R, X, Y)				\
+  _FP_MUL_MEAT_4_wide (_FP_WFRACBITS_Q, R, X, Y, umul_ppmm)
+
+# define _FP_DIV_MEAT_S(R, X, Y)	_FP_DIV_MEAT_1_udiv_norm (S, R, X, Y)
+# define _FP_DIV_MEAT_D(R, X, Y)	_FP_DIV_MEAT_2_udiv (D, R, X, Y)
+# define _FP_DIV_MEAT_Q(R, X, Y)	_FP_DIV_MEAT_4_udiv (Q, R, X, Y)
+
+# define _FP_NANFRAC_S		_FP_QNANBIT_S
+# define _FP_NANFRAC_D		_FP_QNANBIT_D, 0
+# define _FP_NANFRAC_Q		_FP_QNANBIT_Q, 0, 0, 0
+
+#else
+
+# define _FP_W_TYPE_SIZE		64
+# define _FP_W_TYPE		unsigned long long
+# define _FP_WS_TYPE		signed long long
+# define _FP_I_TYPE		long long
+
+# define _FP_MUL_MEAT_S(R, X, Y)					\
+  _FP_MUL_MEAT_1_imm (_FP_WFRACBITS_S, R, X, Y)
+# define _FP_MUL_MEAT_D(R, X, Y)					\
+  _FP_MUL_MEAT_1_wide (_FP_WFRACBITS_D, R, X, Y, umul_ppmm)
+# define _FP_MUL_MEAT_Q(R, X, Y)					\
+  _FP_MUL_MEAT_2_wide_3mul (_FP_WFRACBITS_Q, R, X, Y, umul_ppmm)
+
+# define _FP_DIV_MEAT_S(R, X, Y)	_FP_DIV_MEAT_1_imm (S, R, X, Y, _FP_DIV_HELP_imm)
+# define _FP_DIV_MEAT_D(R, X, Y)	_FP_DIV_MEAT_1_udiv_norm (D, R, X, Y)
+# define _FP_DIV_MEAT_Q(R, X, Y)	_FP_DIV_MEAT_2_udiv (Q, R, X, Y)
+
+# define _FP_NANFRAC_S		_FP_QNANBIT_S
+# define _FP_NANFRAC_D		_FP_QNANBIT_D
+# define _FP_NANFRAC_Q		_FP_QNANBIT_Q, 0
+
+#endif
+
+#define _FP_NANSIGN_S		0
+#define _FP_NANSIGN_D		0
+#define _FP_NANSIGN_Q		0
+
+#define _FP_KEEPNANFRACP 0
+#define _FP_QNANNEGATEDP 0
+
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)	\
+  do {						\
+    R##_s = _FP_NANSIGN_##fs;			\
+    _FP_FRAC_SET_##wc (R, _FP_NANFRAC_##fs);	\
+    R##_c = FP_CLS_NAN;				\
+  } while (0)
+
+#define _FP_DECL_EX		int _frm __attribute__ ((unused));
+#define FP_ROUNDMODE		_frm
+
+#define FP_RND_NEAREST		FE_TONEAREST
+#define FP_RND_ZERO		FE_TOWARDZERO
+#define FP_RND_PINF		FE_UPWARD
+#define FP_RND_MINF		FE_DOWNWARD
+
+#define FP_EX_INVALID		FE_INVALID
+#define FP_EX_OVERFLOW		FE_OVERFLOW
+#define FP_EX_UNDERFLOW		FE_UNDERFLOW
+#define FP_EX_DIVZERO		FE_DIVBYZERO
+#define FP_EX_INEXACT		FE_INEXACT
+
+#define _FP_TININESS_AFTER_ROUNDING 1
+
+#ifdef __riscv_flen
+# define FP_INIT_ROUNDMODE			\
+do {						\
+  __asm__ volatile ("frrm %0" : "=r" (_frm));	\
+} while (0)
+
+# define FP_HANDLE_EXCEPTIONS					\
+do {								\
+  if (__builtin_expect (_fex, 0))				\
+    __asm__ volatile ("csrs fflags, %0" : : "rK" (_fex));	\
+} while (0)
+#else
+# define FP_INIT_ROUNDMODE	_frm = FP_RND_NEAREST
+#endif
diff --git a/sysdeps/riscv/tininess.h b/sysdeps/riscv/tininess.h
new file mode 100644
index 000000000000..1db37790f881
--- /dev/null
+++ b/sysdeps/riscv/tininess.h
@@ -0,0 +1 @@ 
+#define TININESS_AFTER_ROUNDING	1