From cdac1f3a59bcd4bdad675f7c352aefa03d237f96 Mon Sep 17 00:00:00 2001
From: swcompiler <lc@wxiat.com>
Date: Fri, 29 Nov 2024 14:19:24 +0800
Subject: [PATCH 05/23] Sw64: Generic <math.h> and soft-fp Routines

---
 sysdeps/sw_64/fpu/bits/fenv.h | 140 ++++++++++++++++++++++++++++++++++
 sysdeps/sw_64/local-soft-fp.h |  67 ++++++++++++++++
 sysdeps/sw_64/sfp-machine.h   | 105 +++++++++++++++++++++++++
 sysdeps/sw_64/tininess.h      |   1 +
 4 files changed, 313 insertions(+)
 create mode 100644 sysdeps/sw_64/fpu/bits/fenv.h
 create mode 100644 sysdeps/sw_64/local-soft-fp.h
 create mode 100644 sysdeps/sw_64/sfp-machine.h
 create mode 100644 sysdeps/sw_64/tininess.h

diff --git a/sysdeps/sw_64/fpu/bits/fenv.h b/sysdeps/sw_64/fpu/bits/fenv.h
new file mode 100644
index 00000000..ec5dfb8d
--- /dev/null
+++ b/sysdeps/sw_64/fpu/bits/fenv.h
@@ -0,0 +1,140 @@
+/* Copyright (C) 1997-2023 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
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _FENV_H
+#  error "Never use <bits/fenv.h> directly; include <fenv.h> instead."
+#endif
+
+/* Define the bits representing the exception.
+
+   Note that these are the bit positions as defined by the OSF/1
+   ieee_{get,set}_control_word interface and not by the hardware fpcr.
+
+   See the Sw_64 Architecture Handbook section 4.7.7.3 for details,
+   but in summary, trap shadows mean the hardware register can acquire
+   extra exception bits so for proper IEEE support the tracking has to
+   be done in software -- in this case with kernel support.
+
+   As to why the system call interface isn't in the same format as
+   the hardware register, only those crazy folks at DEC can tell you.  */
+
+enum
+{
+#ifdef __USE_GNU
+  FE_DENORMAL =
+#  define FE_DENORMAL (1 << 22)
+      FE_DENORMAL,
+#endif
+
+  FE_INEXACT =
+#define FE_INEXACT (1 << 21)
+      FE_INEXACT,
+
+  FE_UNDERFLOW =
+#define FE_UNDERFLOW (1 << 20)
+      FE_UNDERFLOW,
+
+  FE_OVERFLOW =
+#define FE_OVERFLOW (1 << 19)
+      FE_OVERFLOW,
+
+  FE_DIVBYZERO =
+#define FE_DIVBYZERO (1 << 18)
+      FE_DIVBYZERO,
+
+  FE_INVALID =
+#define FE_INVALID (1 << 17)
+      FE_INVALID,
+
+  FE_ALL_EXCEPT =
+#define FE_ALL_EXCEPT (0x3f << 17)
+      FE_ALL_EXCEPT
+};
+
+/* Sw_64 chips support all four defined rouding modes.
+
+   Note that code must be compiled to use dynamic rounding (/d) instructions
+   to see these changes.  For gcc this is -mfp-rounding-mode=d; for DEC cc
+   this is -fprm d.  The default for both is static rounding to nearest.
+
+   These are shifted down 58 bits from the hardware fpcr because the
+   functions are declared to take integers.  */
+
+enum
+{
+  FE_TOWARDZERO =
+#define FE_TOWARDZERO 0
+      FE_TOWARDZERO,
+
+  FE_DOWNWARD =
+#define FE_DOWNWARD 1
+      FE_DOWNWARD,
+
+  FE_TONEAREST =
+#define FE_TONEAREST 2
+      FE_TONEAREST,
+
+  FE_UPWARD =
+#define FE_UPWARD 3
+      FE_UPWARD,
+};
+
+#ifdef __USE_GNU
+/* On later hardware, and later kernels for earlier hardware, we can forcibly
+   underflow denormal inputs and outputs.  This can speed up certain programs
+   significantly, usually without affecting accuracy.  */
+enum
+{
+  FE_MAP_DMZ = 1UL << 12, /* Map denorm inputs to zero */
+#  define FE_MAP_DMZ FE_MAP_DMZ
+
+  FE_MAP_UMZ = 1UL << 13, /* Map underflowed outputs to zero */
+#  define FE_MAP_UMZ FE_MAP_UMZ
+};
+#endif
+
+/* Type representing exception flags.  */
+typedef unsigned long int fexcept_t;
+
+/* Type representing floating-point environment.  */
+typedef unsigned long int fenv_t;
+
+/* If the default argument is used we use this value.  Note that due to
+   architecture-specified page mappings, no user-space pointer will ever
+   have its two high bits set.  Co-opt one.  */
+#define FE_DFL_ENV ((const fenv_t *) 0x8800000000000000UL)
+
+#ifdef __USE_GNU
+/* Floating-point environment where none of the exceptions are masked.  */
+#  define FE_NOMASK_ENV ((const fenv_t *) 0x880000000000003eUL)
+
+/* Floating-point environment with (processor-dependent) non-IEEE floating
+   point.  In this case, mapping denormals to zero.  */
+#  define FE_NONIEEE_ENV ((const fenv_t *) 0x8800000000003000UL)
+#endif
+
+/* The system calls to talk to the kernel's FP code.  */
+extern unsigned long int __ieee_get_fp_control (void) __THROW;
+extern void __ieee_set_fp_control (unsigned long int __value) __THROW;
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT_C2X)
+/* Type representing floating-point control modes.  */
+typedef unsigned long int femode_t;
+
+/* Default floating-point control modes.  */
+#  define FE_DFL_MODE ((const femode_t *) 0x8800000000000000UL)
+#endif
diff --git a/sysdeps/sw_64/local-soft-fp.h b/sysdeps/sw_64/local-soft-fp.h
new file mode 100644
index 00000000..aab93c30
--- /dev/null
+++ b/sysdeps/sw_64/local-soft-fp.h
@@ -0,0 +1,67 @@
+#include <stdlib.h>
+#include <soft-fp.h>
+#include <quad.h>
+
+/* Helpers for the Ots functions which receive long double arguments
+   in two integer registers, and return values in $16+$17.  */
+
+#define AXP_UNPACK_RAW_Q(X, val)					      \
+  do									  \
+    {									 \
+      union _FP_UNION_Q _flo;						 \
+      _flo.longs.a = val##l;						  \
+      _flo.longs.b = val##h;						  \
+      FP_UNPACK_RAW_QP (X, &_flo);					    \
+    }									 \
+  while (0)
+
+#define AXP_UNPACK_SEMIRAW_Q(X, val)					  \
+  do									  \
+    {									 \
+      union _FP_UNION_Q _flo;						 \
+      _flo.longs.a = val##l;						  \
+      _flo.longs.b = val##h;						  \
+      FP_UNPACK_SEMIRAW_QP (X, &_flo);					\
+    }									 \
+  while (0)
+
+#define AXP_UNPACK_Q(X, val)						  \
+  do									  \
+    {									 \
+      AXP_UNPACK_RAW_Q (X, val);					      \
+      _FP_UNPACK_CANONICAL (Q, 2, X);					 \
+    }									 \
+  while (0)
+
+#define AXP_PACK_RAW_Q(val, X) FP_PACK_RAW_QP (&val##_flo, X)
+
+#define AXP_PACK_SEMIRAW_Q(val, X)					    \
+  do									  \
+    {									 \
+      _FP_PACK_SEMIRAW (Q, 2, X);					     \
+      AXP_PACK_RAW_Q (val, X);						\
+    }									 \
+  while (0)
+
+#define AXP_PACK_Q(val, X)						    \
+  do									  \
+    {									 \
+      _FP_PACK_CANONICAL (Q, 2, X);					   \
+      AXP_PACK_RAW_Q (val, X);						\
+    }									 \
+  while (0)
+
+#define AXP_DECL_RETURN_Q(X) union _FP_UNION_Q X##_flo
+
+/* ??? We don't have a real way to tell the compiler that we're wanting
+   to return values in $16+$17.  Instead use a volatile asm to make sure
+   that the values are live, and just hope that nothing kills the values
+   in between here and the end of the function.  */
+#define AXP_RETURN_Q(X)						       \
+  do									  \
+    {									 \
+      register long r16 __asm__ ("16") = X##_flo.longs.a;		      \
+      register long r17 __asm__ ("17") = X##_flo.longs.b;		      \
+      asm volatile ("" : : "r"(r16), "r"(r17));				\
+    }									 \
+  while (0)
diff --git a/sysdeps/sw_64/sfp-machine.h b/sysdeps/sw_64/sfp-machine.h
new file mode 100644
index 00000000..119e50fc
--- /dev/null
+++ b/sysdeps/sw_64/sfp-machine.h
@@ -0,0 +1,105 @@
+/* Machine-dependent software floating-point definitions.
+   Sw_64 userland IEEE 128-bit version.
+   Copyright (C) 2004-2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@cygnus.com),
+		  Jakub Jelinek (jj@ultra.linux.cz) and
+		  David S. Miller (davem@redhat.com).
+
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fenv_libc.h>
+
+#define _FP_W_TYPE_SIZE 64
+#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_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 (_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 << 1) - 1)
+#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1)
+#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1
+#define _FP_NANSIGN_S 0
+#define _FP_NANSIGN_D 0
+#define _FP_NANSIGN_Q 0
+
+#define _FP_KEEPNANFRACP 1
+#define _FP_QNANNEGATEDP 0
+
+/* Sw_64 Architecture Handbook, 4.7.10.4 sez that we should prefer any
+   type of NaN in Fb, then Fa.  */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP)				    \
+  do									  \
+    {									 \
+      R##_s = Y##_s;							  \
+      _FP_FRAC_COPY_##wc (R, X);					      \
+      R##_c = FP_CLS_NAN;						     \
+    }									 \
+  while (0)
+
+/* Rounding mode settings.  */
+#define FP_RND_NEAREST FE_TONEAREST
+#define FP_RND_ZERO FE_TOWARDZERO
+#define FP_RND_PINF FE_UPWARD
+#define FP_RND_MINF FE_DOWNWARD
+
+/* Obtain the current rounding mode.  It's given as an argument to
+   all the Ots functions, with 4 meaning "dynamic".  */
+#define FP_ROUNDMODE _round
+
+/* Exception flags.  */
+#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
+
+#define FP_INIT_ROUNDMODE						     \
+  do									  \
+    {									 \
+      if (__builtin_expect (_round == 4, 0))				  \
+	{								     \
+	  unsigned long t;						    \
+	  __asm__ __volatile__("excb; rfpcr %0" : "=f"(t));		   \
+	  _round = (t >> FPCR_ROUND_SHIFT) & 3;			       \
+	}								     \
+    }									 \
+  while (0)
+
+/* We copy the libm function into libc for soft-fp.  */
+extern int __feraiseexcept (int __excepts) attribute_hidden;
+
+#define FP_HANDLE_EXCEPTIONS						  \
+  do									  \
+    {									 \
+      if (__builtin_expect (_fex, 0))					 \
+	__feraiseexcept (_fex);					       \
+    }									 \
+  while (0)
+
+#define FP_TRAPPING_EXCEPTIONS						\
+  ((__ieee_get_fp_control () & SWCR_ENABLE_MASK) << SWCR_ENABLE_SHIFT)
diff --git a/sysdeps/sw_64/tininess.h b/sysdeps/sw_64/tininess.h
new file mode 100644
index 00000000..90956c35
--- /dev/null
+++ b/sysdeps/sw_64/tininess.h
@@ -0,0 +1 @@
+#define TININESS_AFTER_ROUNDING 1
-- 
2.25.1

