RISC-V: Generic <math.h> and soft-fp Routines
authorPalmer Dabbelt <palmer@dabbelt.com>
Mon, 29 Jan 2018 18:26:35 +0000 (10:26 -0800)
committerPalmer Dabbelt <palmer@dabbelt.com>
Mon, 29 Jan 2018 18:26:35 +0000 (10:26 -0800)
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.

2018-01-29  Palmer Dabbelt  <palmer@sifive.com>

        * sysdeps/riscv/bits/fenv.h: New file.
        * sysdeps/riscv/e_sqrtl.c: Likewise.
        * sysdeps/riscv/fpu_control.h: Likewise.
        * sysdeps/riscv/math-tests.h: Likewise.
        * sysdeps/riscv/nofpu/Implies: Likewise.
        * sysdeps/riscv/sfp-machine.h: Likewise.
        * sysdeps/riscv/tininess.h: Likewise.

ChangeLog
sysdeps/riscv/bits/fenv.h [new file with mode: 0644]
sysdeps/riscv/e_sqrtl.c [new file with mode: 0644]
sysdeps/riscv/fpu_control.h [new file with mode: 0644]
sysdeps/riscv/math-tests.h [new file with mode: 0644]
sysdeps/riscv/nofpu/Implies [new file with mode: 0644]
sysdeps/riscv/sfp-machine.h [new file with mode: 0644]
sysdeps/riscv/tininess.h [new file with mode: 0644]

index 0ebb348..841440c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        * sysdeps/riscv/nptl/tcb-offsets.sym: Likewise.
        * sysdeps/riscv/nptl/tls.h: Likewise.
        * sysdeps/riscv/stackinfo.h: Likewise.
+       * sysdeps/riscv/bits/fenv.h: New file.
+       * sysdeps/riscv/e_sqrtl.c: Likewise.
+       * sysdeps/riscv/fpu_control.h: Likewise.
+       * sysdeps/riscv/math-tests.h: Likewise.
+       * sysdeps/riscv/nofpu/Implies: Likewise.
+       * sysdeps/riscv/sfp-machine.h: Likewise.
+       * sysdeps/riscv/tininess.h: Likewise.
 
 2018-01-29  Florian Weimer  <fweimer@redhat.com>
 
diff --git a/sysdeps/riscv/bits/fenv.h b/sysdeps/riscv/bits/fenv.h
new file mode 100644 (file)
index 0000000..e23b7e2
--- /dev/null
@@ -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/e_sqrtl.c b/sysdeps/riscv/e_sqrtl.c
new file mode 100644 (file)
index 0000000..55a875d
--- /dev/null
@@ -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/soft-fp.h>
+#include <soft-fp/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/fpu_control.h b/sysdeps/riscv/fpu_control.h
new file mode 100644 (file)
index 0000000..c050d27
--- /dev/null
@@ -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 (file)
index 0000000..32a8356
--- /dev/null
@@ -0,0 +1,42 @@
+/* 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)
+
+/* Despite not supporting trapping exceptions, we support setting
+   floating-point exception flags on hard-float targets.  These are not
+   supported on soft-float targets.  */
+#ifndef __riscv_flen
+# define EXCEPTION_TESTS_float 0
+# define EXCEPTION_TESTS_double        0
+# define EXCEPTION_TESTS_long_double   0
+#endif
+
+/* On soft-float targets we only support the "to nearest" rounding mode.  */
+#ifndef __riscv_flen
+# define ROUNDING_TESTS_float(MODE)            ((MODE) == FE_TONEAREST)
+# define ROUNDING_TESTS_double(MODE)           ((MODE) == FE_TONEAREST)
+# define ROUNDING_TESTS_long_double(MODE)      ((MODE) == FE_TONEAREST)
+#endif
+
+/* 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/nofpu/Implies b/sysdeps/riscv/nofpu/Implies
new file mode 100644 (file)
index 0000000..abcbadb
--- /dev/null
@@ -0,0 +1 @@
+ieee754/soft-fp
diff --git a/sysdeps/riscv/sfp-machine.h b/sysdeps/riscv/sfp-machine.h
new file mode 100644 (file)
index 0000000..e388443
--- /dev/null
@@ -0,0 +1,101 @@
+/* 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
+
+# error "rv32i-based targets are not supported"
+
+#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_MUL_MEAT_DW_S(R, X, Y)                                    \
+  _FP_MUL_MEAT_DW_1_imm (_FP_WFRACBITS_S, R, X, Y)
+# define _FP_MUL_MEAT_DW_D(R, X, Y)                                    \
+  _FP_MUL_MEAT_DW_1_wide (_FP_WFRACBITS_D, R, X, Y, umul_ppmm)
+# define _FP_MUL_MEAT_DW_Q(R, X, Y)                                    \
+  _FP_MUL_MEAT_DW_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 (file)
index 0000000..1db3779
--- /dev/null
@@ -0,0 +1 @@
+#define TININESS_AFTER_ROUNDING        1