floating-point operations broken on hppa
Host environment
- Operating system: Ubuntu 24.04
- OS/kernel version: Linux 6.8.0-83-generic
- Architecture: x86_64
- QEMU flavor: qemu-system-hppa
- QEMU version: 9.2.4, 10.0.5, 10.1.1
- QEMU command line:
qemu-system-hppa -M B160L -m 256 -drive file=t2sde.qcow2,format=qcow2,id=hd0 -nographic -kernel boot/vmlinux-6.16.10-t2 -initrd boot/initrd-6.16.10-t2 -append root=/dev/sda1
Emulated/Virtualized environment
- Operating system: T2SDE 25.10
- OS/kernel version: Linux 6.16.10-t2
- Architecture: hppa
Description of problem
Starting with qemu version 9.2.x, some floating-point operations, especially regarding the floating-point environment, are broken on hppa.
Steps to reproduce
The binaries in https://haible.de/bruno/gnu/qemu-hppa-failing-tests.tar.xz
test-fenv-env-2
test-fenv-env-3
test-fenv-env-4
test-fenv-env-5
test-fenv-except-state-2
test-fenv-except-state-4
test-fenv-except-tracking-1
test-snan-1
are 32-bit hppa binaries, created in two steps:
- Using gnulib, create a compilable directory:
$ ./gnulib-tool --create-testdir --dir=../testdir1 fenv-environment fenv-exceptions-state-c23 fenv-exceptions-tracking-c99 snan
- Build it on a T2SDE 25.10 (https://dl.t2sde.org/binary/2025/t2-25.10-hppa-base-wayland-glibc-gcc.iso) virtual machine, with
CC="gcc -static"
.
These binaries work fine
- on real HPPA hardware (hppadev.matoro.tk),
- in said virtual machine, with qemu versions 8.2.10, 9.0.4, 9.1.3.
These binaries crash due to assertion failures
- in said virtual machine, with qemu versions 9.2.4, 10.0.5, 10.1.1.
Failures:
$ ./test-fenv-env-2
../../gltests/test-fenv-env-2.c:66: assertion '(fetestexcept (FE_ALL_EXCEPT) & ~FE_VXSOFT) == (FE_INVALID | FE_OVERFLOW | FE_INEXACT)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-env-2.c#L66
$ ./test-fenv-env-3
../../gltests/test-fenv-env-3.c:66: assertion '(fetestexcept (FE_ALL_EXCEPT) & ~FE_VXSOFT) == (FE_INVALID | FE_OVERFLOW | FE_INEXACT)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-env-3.c#L66
$ ./test-fenv-env-4
../../gltests/test-fenv-env-4.c:85: assertion 'fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_UNDERFLOW | FE_INEXACT : 0)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-env-4.c#L85
$ ./test-fenv-env-5
../../gltests/test-fenv-env-5.c:87: assertion 'fetestexcept (FE_ALL_EXCEPT) == (supports_tracking ? FE_UNDERFLOW | FE_INEXACT : 0)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-env-5.c#L87
$ ./test-fenv-except-state-2
../../gltests/test-fenv-except-state-2.c:47: assertion 'fetestexcept (FE_INVALID) == FE_INVALID' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-except-state-2.c#L47
$ ./test-fenv-except-state-4
../../gltests/test-fenv-except-state-4.c:44: assertion 'fetestexceptflag (&saved_flags_1, FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT) == (FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW | FE_INEXACT)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-except-state-4.c#L44
$ ./test-fenv-except-tracking-1
../../gltests/test-fenv-except-tracking-1.c:45: assertion 'fetestexcept (FE_ALL_EXCEPT) == FE_ALL_EXCEPT || (fetestexcept (FE_ALL_EXCEPT) & ~FE_VXSOFT) == (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-fenv-except-tracking-1.c#L45
$ ./test-snan-1
../../gltests/test-snan-1.c:75: assertion 'fetestexcept (FE_INVALID)' failed
Source code location: https://github.com/coreutils/gnulib/blob/master/tests/test-snan-1.c#L75
Additional information
What this points to, is that these assembly language statements don't work any more:
/* The status register is located in bits 0 to 31 of floating-point register 0. */
# define _FPU_GETCW(cw) \
({ \
union { __extension__ unsigned long long __fpreg; unsigned int __halfreg[2]; } __fullfp; \
/* Get the current status word. */ \
__asm__ ("fstd %%fr0,0(%1)\n\t" \
"fldd 0(%1),%%fr0\n\t" \
: "=m" (__fullfp.__fpreg) : "r" (&__fullfp.__fpreg) : "%r0"); \
cw = __fullfp.__halfreg[0]; \
})
# define _FPU_SETCW(cw) \
({ \
union { __extension__ unsigned long long __fpreg; unsigned int __halfreg[2]; } __fullfp; \
/* Get the current status word and set the control word. */ \
__asm__ ("fstd %%fr0,0(%1)\n\t" \
: "=m" (__fullfp.__fpreg) : "r" (&__fullfp.__fpreg) : "%r0"); \
__fullfp.__halfreg[0] = cw; \
__asm__ ("fldd 0(%1),%%fr0\n\t" \
: : "m" (__fullfp.__fpreg), "r" (&__fullfp.__fpreg) : "%r0" ); \
})