NetBSD Problem Report #58789

From www@netbsd.org  Tue Oct 29 18:24:24 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 20CE21A9238
	for <gnats-bugs@gnats.NetBSD.org>; Tue, 29 Oct 2024 18:24:24 +0000 (UTC)
Message-Id: <20241029182422.CE37F1A923B@mollari.NetBSD.org>
Date: Tue, 29 Oct 2024 18:24:22 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: aarch64 long double arithmetic is haunted
X-Send-Pr-Version: www-1.0

>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
>Last-Modified:  Tue Oct 29 18:55: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!

>Audit-Trail:
From: Taylor R Campbell <riastradh@NetBSD.org>
To: gnats-bugs@NetBSD.org, netbsd-bugs@NetBSD.org
Cc: 
Subject: Re: port-arm/58789: aarch64 long double arithmetic is haunted
Date: Tue, 29 Oct 2024 18:52:50 +0000

 It seems the reason why the rintl1/rintl2 examples I gave get linked
 against libgcc_s is that libm pulls it in, via --as-needed -lgcc_s:

 $ grep -B2 libgcc_s libm.so.0.map
 As-needed library included to satisfy reference by file (symbol)

 libgcc_s.so.1                 libm_pic.a(s_tanl.pico) (__getf2@@GCC_3.0)
 ...

 (In netbsd-10, it's for __getf2 in csqrtl.pico.  __getf2 is the
 one-argument `tetra-float' (128-bit long double) greater-or-equal
 comparison function.)

 It is unclear to me why libm wants __getf2 out of libgcc_s, but not,
 say, __addtf3 (two-argument `tetra-float' add function), which is also
 defined in both libgcc_s and in libc.

 $ nm -gD --undefined-only libm.so.0 | grep -e __addtf3 -e __getf2
                  U __addtf3
                  U __getf2
 $ readelf -a libm.so.0 | grep -e __addtf3 -e __getf2
 000000060368  012300000402 R_AARCH64_JUMP_SL 0000000000000000 __addtf3@GCC_=
 3.0 + 0
 0000000605f8  01ea00000402 R_AARCH64_JUMP_SL 0000000000000000 __getf2@GCC_3=
 .0 + 0
    291: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __addtf3@GCC_3.0=
  (2)
    490: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __getf2@GCC_3.0 =
 (2)
   1210: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __addtf3@GCC_3.0
   1409: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __getf2@GCC_3.0

 Need a wizard to decipher this ancient elven lore...

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.