Subject: port-i386/36770: "long double" arithmetics doesn't work on i386
To: None <port-i386-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <M.Drochner@fz-juelich.de>
List: netbsd-bugs
Date: 08/10/2007 21:45:00
>Number:         36770
>Category:       port-i386
>Synopsis:       "long double" arithmetics doesn't work on i386
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    port-i386-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Aug 10 21:45:00 +0000 2007
>Originator:     Matthias Drochner
>Release:        current/i386
>Organization:
>Environment:
gcc version 4.1.3 20070620 prerelease (NetBSD nb1 20070620)
>Description:
This seems to be a toolchain issue.
Appearently, gcc fails to emit instuctions which set the i387
floating point control word to 64-bit rounding where "long double"
data types are used. This makes that 53-bit rounding is used which
is the default on NetBSD (for good reasons afaiu).
So one doesn't get additional precision from the use of "long double".

>How-To-Repeat:
Try the program below (taken from an sqlite3 selftest).
"xxx" implements a poor man's atof(); while it doesn't do proper
rounding the use of "long double" internally should make that
the "double" result is correct anyway (as is the result of atof(),
for comparision).
Setting the FPCW, as done in the "#ifdef FIX" part, makes that
the result is correct. This should be done by gcc automatically.


#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

double
xxx(const char *s)
{
        long double r = 0.0;

#ifdef FIX
        const int fpcw = 0x37f;
        asm("fldcw %0"::"m"(fpcw));
#endif

        while (isdigit(*s)) {
                r = r * 10.0 + (*s - '0');
                s++;
        }
        return r;
}

main()
{
        const char in[] = "9223372036854774800";
        double f = xxx(in);
        double g = atof(in);
        printf("%s %.20g %.20g\n", in, f, g);
}

>Fix:
For now I can only tell that setting TARGET_96_ROUND_53_LONG_DOUBLE
in the gcc configuration doesn't help.