From cdac1f3a59bcd4bdad675f7c352aefa03d237f96 Mon Sep 17 00:00:00 2001 From: swcompiler Date: Fri, 29 Nov 2024 14:19:24 +0800 Subject: [PATCH 05/23] Sw64: Generic 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 + . */ + +#ifndef _FENV_H +# error "Never use directly; include 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 +#include +#include + +/* 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 + . */ + +#include + +#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