mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-22 13:00:06 +00:00
643d9d38d5
This patch adds hardware floating point support to OpenRISC. Hardware floating point toolchain builds are enabled by passing the machine specific argument -mhard-float to gcc via CFLAGS. With this enabled GCC generates floating point instructions for single-precision operations and exports __or1k_hard_float__. There are 2 main parts to this patch. - Implement fenv functions to update the FPCSR flags keeping it in sync with sfp (software floating point). - Update machine context functions to store and restore the FPCSR state. *On mcontext_t ABI* This patch adds __fpcsr to mcontext_t. This is an ABI change, but also an ABI fix. The Linux kernel has always defined padding in mcontext_t that space was missing from the glibc ABI. In Linux this unused space has now been re-purposed for storing the FPCSR. This patch brings OpenRISC glibc in line with the Linux kernel and other libc implementation (musl). Compatibility getcontext, setcontext, etc symbols have been added to allow for binaries expecting the old ABI to continue to work. *Hard float ABI* The calling conventions and types do not change with OpenRISC hard-float so glibc hard-float builds continue to use dynamic linker /lib/ld-linux-or1k.so.1. *Testing* I have tested this patch both with hard-float and soft-float builds and the test results look fine to me. Results are as follows: Hard Float # failures FAIL: elf/tst-sprof-basic (Haven't figured out yet, not related to hard-float) FAIL: gmon/tst-gmon-pie (PIE bug in or1k toolchain) FAIL: gmon/tst-gmon-pie-gprof (PIE bug in or1k toolchain) FAIL: iconvdata/iconv-test (timeout, passed when run manually) FAIL: nptl/tst-cond24 (Timeout) FAIL: nptl/tst-mutex10 (Timeout) # summary 6 FAIL 4289 PASS 86 UNSUPPORTED 16 XFAIL 2 XPASS # versions Toolchain: or1k-smhfpu-linux-gnu Compiler: gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC) Binutils: GNU assembler version 2.42.0 (or1k-smhfpu-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324 Linux: Linux buildroot 6.9.0-rc1-00008-g4dc70e1aadfa #112 SMP Sat Apr 27 06:43:11 BST 2024 openrisc GNU/Linux Tester: shorne Glibc: 2024-04-25b62928f907
Florian Weimer x86: In ld.so, diagnose missing APX support in APX-only builds (origin/master, origin/HEAD) Soft Float # failures FAIL: elf/tst-sprof-basic FAIL: gmon/tst-gmon-pie FAIL: gmon/tst-gmon-pie-gprof FAIL: nptl/tst-cond24 FAIL: nptl/tst-mutex10 # summary 5 FAIL 4295 PASS 81 UNSUPPORTED 16 XFAIL 2 XPASS # versions Toolchain: or1k-smh-linux-gnu Compiler: gcc version 14.0.1 20240324 (experimental) [master r14-9649-gbb04a11418f] (GCC) Binutils: GNU assembler version 2.42.0 (or1k-smh-linux-gnu) using BFD version (GNU Binutils) 2.42.0.20240324 Linux: Linux buildroot 6.9.0-rc1-00008-g4dc70e1aadfa #112 SMP Sat Apr 27 06:43:11 BST 2024 openrisc GNU/Linux Tester: shorne Glibc: 2024-04-25b62928f907
Florian Weimer x86: In ld.so, diagnose missing APX support in APX-only builds (origin/master, origin/HEAD) Documentation: https://raw.githubusercontent.com/openrisc/doc/master/openrisc-arch-1.4-rev0.pdf Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
200 lines
5.2 KiB
C
200 lines
5.2 KiB
C
/* Private floating point rounding and exceptions handling. OpenRISC version.
|
|
Copyright (C) 2024 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 OR1K_FENV_PRIVATE_H
|
|
#define OR1K_FENV_PRIVATE_H 1
|
|
|
|
#include <fenv.h>
|
|
#include <fpu_control.h>
|
|
|
|
static __always_inline void
|
|
libc_feholdexcept_or1k (fenv_t *envp)
|
|
{
|
|
fpu_control_t cw;
|
|
fpu_control_t cw_new;
|
|
|
|
/* Get and store the environment. */
|
|
_FPU_GETCW (cw);
|
|
*envp = cw;
|
|
|
|
/* Clear the exception status flags. */
|
|
cw_new = cw & ~FE_ALL_EXCEPT;
|
|
|
|
if (cw != cw_new)
|
|
_FPU_SETCW (cw_new);
|
|
}
|
|
|
|
#define libc_feholdexcept libc_feholdexcept_or1k
|
|
#define libc_feholdexceptf libc_feholdexcept_or1k
|
|
#define libc_feholdexceptl libc_feholdexcept_or1k
|
|
|
|
static __always_inline void
|
|
libc_fesetround_or1k (int round)
|
|
{
|
|
fpu_control_t cw;
|
|
fpu_control_t cw_new;
|
|
|
|
_FPU_GETCW (cw);
|
|
cw_new = cw & ~_FPU_FPCSR_RM_MASK;
|
|
cw_new |= round;
|
|
if (cw != cw_new)
|
|
_FPU_SETCW (cw_new);
|
|
}
|
|
|
|
#define libc_fesetround libc_fesetround_or1k
|
|
#define libc_fesetroundf libc_fesetround_or1k
|
|
#define libc_fesetroundl libc_fesetround_or1k
|
|
|
|
static __always_inline void
|
|
libc_feholdexcept_setround_or1k (fenv_t *envp, int round)
|
|
{
|
|
fpu_control_t cw;
|
|
fpu_control_t cw_new;
|
|
|
|
/* Get and store the environment. */
|
|
_FPU_GETCW (cw);
|
|
*envp = cw;
|
|
|
|
/* Clear the status flags and rounding mode. */
|
|
cw_new = cw & ~(FE_ALL_EXCEPT | _FPU_FPCSR_RM_MASK);
|
|
|
|
/* Set rounding mode. */
|
|
cw_new |= round;
|
|
|
|
if (cw != cw_new)
|
|
_FPU_SETCW (cw_new);
|
|
}
|
|
|
|
#define libc_feholdexcept_setround libc_feholdexcept_setround_or1k
|
|
#define libc_feholdexcept_setroundf libc_feholdexcept_setround_or1k
|
|
#define libc_feholdexcept_setroundl libc_feholdexcept_setround_or1k
|
|
|
|
static __always_inline int
|
|
libc_fetestexcept_or1k (int ex)
|
|
{
|
|
fpu_control_t cw;
|
|
|
|
/* Get current control word. */
|
|
_FPU_GETCW (cw);
|
|
|
|
/* Check if any of the queried exception flags are set. */
|
|
return cw & ex & FE_ALL_EXCEPT;
|
|
}
|
|
|
|
#define libc_fetestexcept libc_fetestexcept_or1k
|
|
#define libc_fetestexceptf libc_fetestexcept_or1k
|
|
#define libc_fetestexceptl libc_fetestexcept_or1k
|
|
|
|
static __always_inline void
|
|
libc_fesetenv_or1k (const fenv_t *envp)
|
|
{
|
|
if (envp == FE_DFL_ENV)
|
|
_FPU_SETCW (_FPU_DEFAULT);
|
|
else
|
|
_FPU_SETCW (*envp);
|
|
}
|
|
|
|
#define libc_fesetenv libc_fesetenv_or1k
|
|
#define libc_fesetenvf libc_fesetenv_or1k
|
|
#define libc_fesetenvl libc_fesetenv_or1k
|
|
#define libc_feresetround_noex libc_fesetenv_or1k
|
|
#define libc_feresetround_noexf libc_fesetenv_or1k
|
|
#define libc_feresetround_noexl libc_fesetenv_or1k
|
|
|
|
static __always_inline int
|
|
libc_feupdateenv_test_or1k (const fenv_t *envp, int ex)
|
|
{
|
|
fpu_control_t cw;
|
|
fpu_control_t cw_new;
|
|
int excepts;
|
|
|
|
/* Get current control word. */
|
|
_FPU_GETCW (cw);
|
|
|
|
/* Merge current exception flags with the passed fenv. */
|
|
excepts = cw & FE_ALL_EXCEPT;
|
|
cw_new = (envp == FE_DFL_ENV ? _FPU_DEFAULT : *envp) | excepts;
|
|
|
|
if (__glibc_unlikely (cw != cw_new))
|
|
_FPU_SETCW (cw_new);
|
|
|
|
/* Raise the exceptions if enabled in the new FP state. */
|
|
if (__glibc_unlikely (excepts))
|
|
__feraiseexcept (excepts);
|
|
|
|
return excepts & ex;
|
|
}
|
|
|
|
#define libc_feupdateenv_test libc_feupdateenv_test_or1k
|
|
#define libc_feupdateenv_testf libc_feupdateenv_test_or1k
|
|
#define libc_feupdateenv_testl libc_feupdateenv_test_or1k
|
|
|
|
static __always_inline void
|
|
libc_feupdateenv_or1k (const fenv_t *envp)
|
|
{
|
|
libc_feupdateenv_test_or1k (envp, 0);
|
|
}
|
|
|
|
#define libc_feupdateenv libc_feupdateenv_or1k
|
|
#define libc_feupdateenvf libc_feupdateenv_or1k
|
|
#define libc_feupdateenvl libc_feupdateenv_or1k
|
|
|
|
static __always_inline void
|
|
libc_feholdsetround_or1k (fenv_t *envp, int round)
|
|
{
|
|
fpu_control_t cw;
|
|
|
|
_FPU_GETCW (cw);
|
|
*envp = cw;
|
|
|
|
/* Check whether rounding modes are different. */
|
|
round = (cw ^ round) & _FPU_FPCSR_RM_MASK;
|
|
|
|
/* Set new rounding mode if different. */
|
|
if (__glibc_unlikely (round != 0))
|
|
_FPU_SETCW (cw ^ round);
|
|
}
|
|
|
|
#define libc_feholdsetround libc_feholdsetround_or1k
|
|
#define libc_feholdsetroundf libc_feholdsetround_or1k
|
|
#define libc_feholdsetroundl libc_feholdsetround_or1k
|
|
|
|
static __always_inline void
|
|
libc_feresetround_or1k (fenv_t *envp)
|
|
{
|
|
fpu_control_t cw;
|
|
int round;
|
|
|
|
_FPU_GETCW (cw);
|
|
|
|
/* Check whether rounding modes are different. */
|
|
round = (*envp ^ cw) & _FPU_FPCSR_RM_MASK;
|
|
|
|
/* Restore the rounding mode if it was changed. */
|
|
if (__glibc_unlikely (round != 0))
|
|
_FPU_SETCW (cw ^ round);
|
|
}
|
|
|
|
#define libc_feresetround libc_feresetround_or1k
|
|
#define libc_feresetroundf libc_feresetround_or1k
|
|
#define libc_feresetroundl libc_feresetround_or1k
|
|
|
|
#include_next <fenv_private.h>
|
|
|
|
#endif
|