NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

port-arm/58782: fpsetround flips all the other fpcsr bits on aarch64



>Number:         58782
>Category:       port-arm
>Synopsis:       fpsetround flips all the other fpcsr bits on aarch64
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-arm-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Oct 28 21:30:00 +0000 2024
>Originator:     Taylor R Campbell
>Release:        current, 10, 9
>Organization:
The NetBSD Roundfliption
>Environment:
>Description:
The aarch64 implementation of fpsetround() from <ieeefp.h> has the effect of flipping all bits _other_ than the rounding mode in the fpcr, the floating-point control register.

     48 	const uint32_t old_fpcr = reg_fpcr_read();
     49 	const uint32_t new_fpcr = (~old_fpcr & ~FPCR_RMODE)
     50 	    | __SHIFTIN(rnd, FPCR_RMODE);
     51 	reg_fpcr_write(new_fpcr);

https://nxr.netbsd.org/xref/src/lib/libc/arch/aarch64/gen/fpsetround.c?r=1.3#49

As a result, for example, setting the rounding mode has the side effect of toggling flush-to-zero (no gradual underflow) mode.
>How-To-Repeat:
$ cat noftz.c
#include <float.h>
#include <ieeefp.h>
#include <stdio.h>

int
main(void)
{
	volatile double x = DBL_MIN;
	volatile double y;

	y = x/2;
	printf("%a\n", y);
	fpsetround(FP_RN);
	y = x/2;
	printf("%a\n", y);
	fpsetround(FP_RN);
	y = x/2;
	printf("%a\n", y);
	fflush(stdout);
	return ferror(stdout);
}
$ make ftz
cc -O2    -o ftz ftz.c 
$ ./ftz
0x1p-1023
0x0p+0
0x1p-1023

>Fix:
nix the extra ~



Home | Main Index | Thread Index | Old Index