NetBSD-Bugs archive

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

port-arm/58789: aarch64 long double arithmetic is haunted



>Number:         58789
>Category:       port-arm
>Synopsis:       aarch64 long double arithmetic is haunted
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-arm-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Oct 29 18:25:01 +0000 2024
>Originator:     Taylor R Campbell
>Release:        current
>Organization:
The Haunted NetBSD Rintlation
>Environment:
>Description:
Since the resolution to PR lib/57021 (libc __trunctfdf2 conflicts with libgcc on aarch64), we have, on aarch64:

- compiler-rt softfloat128 long double arithmetic linked into libc.so
- libgcc softfloat128 long double arithmetic defined in libgcc_s.so
- executables linked against both by default

The long double arithmetic symbols in question are symbols like __addtf3 and __subtf3.

The two implementations, from compiler-rt and libgcc, are not quite compatible.  For example, compiler-rt softfloat128 long double arithmetic has no concept of floating-point rounding mode, while gcc softfloat128 long double arithmetic respects the rounding mode set in the FPCR (floating-point control register).

I suspect this is why long double functions such as rintl exhibit haunted behaviour like the example below.
>How-To-Repeat:
$ cat rintl1.c
#include <fenv.h>
#include <math.h>
#include <unistd.h>

int
main(void)
{
	volatile long double x = 0x2.00000000000008p+52L;
	volatile long double y, z;
	volatile int c;

	y = rintl(x);
	fesetround(FE_UPWARD);
	z = rintl(x);
	c = x ? 0 : 1;
	write(STDOUT_FILENO, __UNVOLATILE(&y), sizeof(y));
	write(STDOUT_FILENO, __UNVOLATILE(&z), sizeof(z));
	return c;
}
$ cat rintl2.c
#include <fenv.h>
#include <math.h>
#include <unistd.h>

int
main(void)
{
	volatile long double x = 0x2.00000000000008p+52L;
	volatile long double y, z;
	volatile int c;

	y = rintl(x);
	fesetround(FE_UPWARD);
	z = rintl(x);
	c = 1 ? 0 : 1;
	write(STDOUT_FILENO, __UNVOLATILE(&y), sizeof(y));
	write(STDOUT_FILENO, __UNVOLATILE(&z), sizeof(z));
	return c;
}
$ diff -u rintl1.c rintl2.c
--- rintl1.c	2024-10-29 12:48:29.000000000 +0000
+++ rintl2.c	2024-10-29 12:48:09.000000000 +0000
@@ -12,7 +12,7 @@
 	y = rintl(x);
 	fesetround(FE_UPWARD);
 	z = rintl(x);
-	c = x ? 0 : 1;
+	c = 1 ? 0 : 1;
 	write(STDOUT_FILENO, __UNVOLATILE(&y), sizeof(y));
 	write(STDOUT_FILENO, __UNVOLATILE(&z), sizeof(z));
 	return c;
$ make rintl1 rintl2 LDLIBS=-lm DBG=-g\ -O2\ -Wall\ -Werror
cc -g -O2 -Wall -Werror    -o rintl1 rintl1.c -lm
cc -g -O2 -Wall -Werror    -o rintl2 rintl2.c -lm
$ ./rintl1 | hexdump -C
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 34 40  |..............4@|
00000010  00 00 00 00 00 00 00 08  00 00 00 00 00 00 34 40  |..............4@|
00000020
$ ./rintl2 | hexdump -C
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 34 40  |..............4@|
*
00000020

>Fix:
Yes, please!



Home | Main Index | Thread Index | Old Index