[PATCH v2] LoongArch: fix missing trap for enabled exceptions on narrowing operation
caiyinyu
caiyinyu@loongson.cn
Fri Mar 20 09:52:52 GMT 2026
LGTM
在 2026/3/20 下午5:12, Xi Ruoyao 写道:
> The libc_feupdateenv_test macro is supposed to trap when the trap for a
> previously held exception is enabled. But
> libc_feupdateenv_test_loongarch wasn't doing it properly: the comment
> claims "setting of the cause bits" would cause "the hardware to generate
> the exception" but that's simply not true for the LoongArch movgr2fcsr
> instruction.
>
> To fix the issue, we need to call __feraiseexcept in case a held exception
> is enabled to trap.
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
>
> Change from v1:
> - Fix a leftover from earlier debugging in the test case, which caused
> test failures on 32-bit LoongArch and ARM.
> - Simplify the test using glibc test framework.
>
> math/Makefile | 3 ++
> math/test-narrowing-trap.c | 60 ++++++++++++++++++++++++++++++++
> sysdeps/loongarch/fenv_private.h | 22 ++++++------
> sysdeps/loongarch/fpu_control.h | 3 ++
> 4 files changed, 77 insertions(+), 11 deletions(-)
> create mode 100644 math/test-narrowing-trap.c
>
> diff --git a/math/Makefile b/math/Makefile
> index 2eb0085de9..7a9352c2cd 100644
> --- a/math/Makefile
> +++ b/math/Makefile
> @@ -563,6 +563,7 @@ tests = \
> test-nan-overflow \
> test-nan-payload \
> test-narrow-macros \
> + test-narrowing-trap \
> test-nearbyint-except \
> test-nearbyint-except-2 \
> test-powl \
> @@ -1172,6 +1173,8 @@ CFLAGS-test-ceil-except-2.c += -fno-builtin
> CFLAGS-test-floor-except-2.c += -fno-builtin
> CFLAGS-test-trunc-except-2.c += -fno-builtin
>
> +CFLAGS-test-narrowing-trap.c += -fno-builtin
> +
> include ../Rules
>
> gen-all-calls = $(gen-libm-calls) $(gen-calls)
> diff --git a/math/test-narrowing-trap.c b/math/test-narrowing-trap.c
> new file mode 100644
> index 0000000000..27c31245c1
> --- /dev/null
> +++ b/math/test-narrowing-trap.c
> @@ -0,0 +1,60 @@
> +/* Copyright (C) 2026 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 _GNU_SOURCE
> +# define _GNU_SOURCE
> +#endif
> +
> +#include <fenv.h>
> +#include <math.h>
> +#include <math-tests.h>
> +#include <signal.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/xunistd.h>
> +
> +static int
> +do_test (void)
> +{
> + pid_t pid;
> +
> + if (!EXCEPTION_ENABLE_SUPPORTED (FE_INVALID))
> + FAIL_UNSUPPORTED ("feenableexcept (FE_INVALID) not supported");
> +
> + pid = xfork ();
> + if (pid == 0)
> + {
> + int r = feenableexcept (FE_INVALID);
> + if (r == -1)
> + exit (2);
> +
> + fdiv (0.0, 0.0);
> + exit (0);
> + }
> + else
> + {
> + int status;
> + xwaitpid (pid, &status, 0);
> +
> + TEST_VERIFY (WIFSIGNALED (status));
> + TEST_COMPARE (WTERMSIG (status), SIGFPE);
> + }
> +
> + return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/loongarch/fenv_private.h b/sysdeps/loongarch/fenv_private.h
> index 7b49d82527..f782447fa2 100644
> --- a/sysdeps/loongarch/fenv_private.h
> +++ b/sysdeps/loongarch/fenv_private.h
> @@ -115,20 +115,20 @@ static __always_inline int
> libc_feupdateenv_test_loongarch (fenv_t *envp, int excepts)
> {
> /* int ret = fetestexcept (excepts); feupdateenv (envp); return ret; */
> - int cw, temp;
> + int held_ex, cw = envp->__fp_control_register;
>
> - /* Get current control word. */
> - _FPU_GETCW (cw);
> + /* Get the current flag, i.e. all exceptions raised since we started
> + to hold the exceptions. We don't care CAUSE. */
> + _FPU_GET_FLAGS_CAUSE (held_ex);
>
> - /* Set flag bits (which are accumulative), and *also* set the
> - cause bits. The setting of the cause bits is what actually causes
> - the hardware to generate the exception, if the corresponding enable
> - bit is set as well. */
> - temp = cw & FE_ALL_EXCEPT;
> - temp |= envp->__fp_control_register | (temp << CAUSE_SHIFT);
> + /* Set flag bits (which are accumulative). */
> + cw |= held_ex;
> + _FPU_SETCW (cw);
>
> - /* Set new state. */
> - _FPU_SETCW (temp);
> + /* Raise SIGFPE for any new exceptions since the hold, in case any is
> + enabled. */
> + if (__glibc_unlikely (((cw & ENABLE_MASK) << ENABLE_SHIFT) & held_ex))
> + __feraiseexcept (held_ex);
>
> return cw & excepts & FE_ALL_EXCEPT;
> }
> diff --git a/sysdeps/loongarch/fpu_control.h b/sysdeps/loongarch/fpu_control.h
> index 95976fa192..4d9dd52fca 100644
> --- a/sysdeps/loongarch/fpu_control.h
> +++ b/sysdeps/loongarch/fpu_control.h
> @@ -97,6 +97,9 @@ extern void __loongarch_fpu_setcw (fpu_control_t) __THROW;
> #define _FPU_GET_ENABLES(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr1" : "=r"(cw))
> #define _FPU_SET_ENABLES(cw) __asm__ volatile ("movgr2fcsr $fcsr1,%0" : : "r"(cw))
>
> +#define _FPU_GET_FLAGS_CAUSE(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr2" : "=r"(cw))
> +#define _FPU_SET_FLAGS_CAUSE(cw) __asm__ volatile ("movgr2fcsr $fcsr2,%0" : : "r"(cw))
> +
> #define _FPU_GET_RM(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr3" : "=r"(cw))
> #define _FPU_SET_RM(cw) __asm__ volatile ("movgr2fcsr $fcsr3,%0" : : "r"(cw))
>
More information about the Libc-alpha
mailing list