Bug 242067 - libc: r354823 riscv64 has a fault in printf() where IEEE754-2008 fp128 data is output wrong
Summary: libc: r354823 riscv64 has a fault in printf() where IEEE754-2008 fp128 data i...
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: CURRENT
Hardware: riscv Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords: needs-qa
Depends on:
Blocks:
 
Reported: 2019-11-19 03:15 UTC by Dennis Clarke
Modified: 2020-07-06 15:01 UTC (History)
3 users (show)

See Also:
koobs: maintainer-feedback? (br)
koobs: maintainer-feedback? (emaste)
koobs: maintainer-feedback? (mhorne)


Attachments
Log of compile and output of assembly and check of fp128 data. (16.37 KB, text/plain)
2019-11-19 03:15 UTC, Dennis Clarke
no flags Details
Assemble , compile and link and check results. (32.74 KB, text/plain)
2019-11-19 03:18 UTC, Dennis Clarke
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Dennis Clarke 2019-11-19 03:15:06 UTC
Created attachment 209239 [details]
Log of compile and output of assembly and check of fp128 data.

I tested this on both r351523 ppc64 and riscv r350568 as well as the
recent jenkins r354823 where valid and reasonable fp128 little endian
data is mis-reported via printf thus : 


/*************************************************
 * The Open Group Base Specifications Issue 6
 * IEEE Std 1003.1, 2004 Edition
 *************************************************/
#define _XOPEN_SOURCE 600

#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <sys/utsname.h>

int main ( int argc, char *argv[] ) {

    /* note hex representation of pi is 
     *   0x4000 0x921f 0xb544 0x42d1 0x8469 0x898c 0xc517 0x01b8
     * IEEE754-2008 binary64 hex representation of pi is
     *    40 09 21 fb 54 44 2d 18   */
    int j;

    long double pi = 3.14159265358979323846264338327950288419716939937510L;

    struct utsname uname_data;

    setlocale( LC_MESSAGES, "C" );
    if ( uname( &uname_data ) < 0 ) {
        fprintf ( stderr,
                 "WARNING : Could not attain system uname data.\n" );
        perror ( "uname" );
    } else {
        printf ( "-------------------------------" );
        printf ( "------------------------------\n" );
        printf ( "        system name = %s\n", uname_data.sysname );
        printf ( "          node name = %s\n", uname_data.nodename );
        printf ( "            release = %s\n", uname_data.release );
        printf ( "            version = %s\n", uname_data.version );
        printf ( "            machine = %s\n", uname_data.machine );
        printf ( "-------------------------------" );
        printf ( "------------------------------" );
    }
    printf ("\n");

    uint8_t x86_fp80[16] = { 0x35, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9,
                             0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    printf("x86_fp80[16]\n");
    printf("    0x35, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9,\n");
    printf("    0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n");
    printf("out ");
    for ( j=0; j<16; j++ ) {
        printf("0x%02x ", ((uint8_t *)&x86_fp80)[j] );
    }
    printf("\n");
    printf("    x86_fp80 may be %38.34Le\n", *(long double*)&x86_fp80);
    printf("    x86_fp80  or be %18.14g\n", *(double*)&x86_fp80);
    printf("-------------------------------------------------\n");


    uint8_t pi_fp64le[16] = { 0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,
                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    printf("pi_fp64le[16]\n");
    printf("    0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,\n");
    printf("    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n");
    printf("out ");
    for ( j=0; j<16; j++ ) {
        printf("0x%02x ", ((uint8_t *)&pi_fp64le)[j] );
    }
    printf("\n");
    printf("   pi_fp64le may be %38.34Le\n", *(long double*)&pi_fp64le);
    printf("   pi_fp64le  or be %18.14g\n", *(double*)&pi_fp64le);
    printf("-------------------------------------------------\n");


    uint8_t pi_fp64be[16] = { 0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    printf("pi_fp64be[16]\n");
    printf("    0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,\n");
    printf("    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n");
    printf("out ");
    for ( j=0; j<16; j++ ) {
        printf("0x%02x ", ((uint8_t *)&pi_fp64be)[j] );
    }
    printf("\n");
    printf("   pi_fp64be may be %38.34Le\n", *(long double*)&pi_fp64be);
    printf("   pi_fp64be  or be %18.14g\n", *(double*)&pi_fp64be);
    printf("-------------------------------------------------\n");


    uint8_t pi_fp128le[16] = { 0xb8, 0x01, 0x17, 0xc5, 0x8c, 0x89, 0x69, 0x84,
                               0xd1, 0x42, 0x44, 0xb5, 0x1f, 0x92, 0x00, 0x40 };
    printf("pi_fp128le[16]\n");
    printf("    0xb8, 0x01, 0x17, 0xc5, 0x8c, 0x89, 0x69, 0x84,\n");
    printf("    0xd1, 0x42, 0x44, 0xb5, 0x1f, 0x92, 0x00, 0x40\n");
    printf("out ");
    for ( j=0; j<16; j++ ) {
        printf("0x%02x ", ((uint8_t *)&pi_fp128le)[j] );
    }
    printf("\n");
    printf("  pi_fp128le may be %38.34Le\n", *(long double*)&pi_fp128le);
    printf("  pi_fp128le  or be %18.14g\n", *(double*)&pi_fp128le); 
    printf("-------------------------------------------------\n");

    uint8_t pi_fp128be[16] = { 0x40, 0x00, 0x92, 0x1f, 0xb5, 0x44, 0x42, 0xd1,
                               0x84, 0x69, 0x89, 0x8c, 0xc5, 0x17, 0x01, 0xb8 };
    printf("pi_fp128be[16]\n");
    printf("    0x40, 0x00, 0x92, 0x1f, 0xb5, 0x44, 0x42, 0xd1,\n");
    printf("    0x84, 0x69, 0x89, 0x8c, 0xc5, 0x17, 0x01, 0xb8\n");
    printf("out ");
    for ( j=0; j<16; j++ ) {
        printf("0x%02x ", ((uint8_t *)&pi_fp128be)[j] );
    }
    printf("\n");       
    printf("  pi_fp128be may be %38.34Le\n", *(long double*)&pi_fp128be);
    printf("  pi_fp128be  or be %18.14g\n", *(double*)&pi_fp128be);
    printf("-------------------------------------------------\n");

    for ( j=0; j<sizeof(long double); j++ )
        printf("%02x ", ((unsigned char *)&pi)[j] );

    printf("\n" );

    printf("pi may be %38.34Le\n", pi);

    return (EXIT_SUCCESS);
}

The output from the above on a Solaris 10 Fujitsu sparcv9 server is 
correctly : 

beta $ 
beta $ /opt/bw/gcc9/bin/gcc -std=iso9899:1999 -pedantic -fno-builtin -g -m64 -o hex_hack hex_hack.c 
beta $ 
beta $ ./hex_hack
-------------------------------------------------------------
        system name = SunOS
          node name = beta
            release = 5.10
            version = Generic_150400-65
            machine = sun4u
-------------------------------------------------------------
x86_fp80[16]
    0x35, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9,
    0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x35 0xc2 0x68 0x21 0xa2 0xda 0x0f 0xc9 0x00 0x40 0x00 0x00 0x00 0x00 0x00 0x00 
    x86_fp80 may be 1.4079991028348808823621394844517895e-789
    x86_fp80  or be 9.839389446594e-50
-------------------------------------------------
pi_fp64le[16]
    0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x18 0x2d 0x44 0x54 0xfb 0x21 0x09 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
   pi_fp64le may be 2.5291464540223296389757969198439224e-3069
   pi_fp64le  or be 3.2073756306764e-192
-------------------------------------------------
pi_fp64be[16]
    0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x40 0x09 0x21 0xfb 0x54 0x44 0x2d 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
   pi_fp64be may be 1.1599270182075852062553167343139648e+03
   pi_fp64be  or be    3.1415926535898
-------------------------------------------------
pi_fp128le[16]
    0xb8, 0x01, 0x17, 0xc5, 0x8c, 0x89, 0x69, 0x84,
    0xd1, 0x42, 0x44, 0xb5, 0x1f, 0x92, 0x00, 0x40
out 0xb8 0x01 0x17 0xc5 0x8c 0x89 0x69 0x84 0xd1 0x42 0x44 0xb5 0x1f 0x92 0x00 0x40 
  pi_fp128le may be -1.3526724668465106417844259659978911e-616
  pi_fp128le  or be -6.2789244204581e-39
-------------------------------------------------
pi_fp128be[16]
    0x40, 0x00, 0x92, 0x1f, 0xb5, 0x44, 0x42, 0xd1,
    0x84, 0x69, 0x89, 0x8c, 0xc5, 0x17, 0x01, 0xb8
out 0x40 0x00 0x92 0x1f 0xb5 0x44 0x42 0xd1 0x84 0x69 0x89 0x8c 0xc5 0x17 0x01 0xb8 
  pi_fp128be may be 3.1415926535897932384626433832795028e+00
  pi_fp128be  or be    2.0713495408494
-------------------------------------------------
40 00 92 1f b5 44 42 d1 84 69 89 8c c5 17 01 b8 
pi may be 3.1415926535897932384626433832795028e+00
beta $ 

Whereas the AMD Opteron based FreeBSD 12.1 release will report the best
intel fp80 format data thus : 

vesta$ 
vesta$ ./hex_hack
-------------------------------------------------------------
        system name = FreeBSD
          node name = vesta
            release = 12.1-RELEASE
            version = FreeBSD 12.1-RELEASE r354233 GENERIC
            machine = amd64
-------------------------------------------------------------
x86_fp80[16]
    0x35, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9,
    0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x35 0xc2 0x68 0x21 0xa2 0xda 0x0f 0xc9 0x00 0x40 0x00 0x00 0x00 0x00 0x00 0x00 
    x86_fp80 may be 3.1415926535897932385128089594061862e+00
    x86_fp80  or be -8.8796093704934e+43
-------------------------------------------------
pi_fp64le[16]
    0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x18 0x2d 0x44 0x54 0xfb 0x21 0x09 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
   pi_fp64le may be 1.6819886204449109911174915236564559e-4932
   pi_fp64le  or be    3.1415926535898
-------------------------------------------------
pi_fp64be[16]
    0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x40 0x09 0x21 0xfb 0x54 0x44 0x2d 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
   pi_fp64be may be 6.3503887240691950845592893794047029e-4933
   pi_fp64be  or be 3.2073756306764e-192
-------------------------------------------------
pi_fp128le[16]
    0xb8, 0x01, 0x17, 0xc5, 0x8c, 0x89, 0x69, 0x84,
    0xd1, 0x42, 0x44, 0xb5, 0x1f, 0x92, 0x00, 0x40
out 0xb8 0x01 0x17 0xc5 0x8c 0x89 0x69 0x84 0xd1 0x42 0x44 0xb5 0x1f 0x92 0x00 0x40 
  pi_fp128le may be 2.2823123577349716480961329732730512e+217
  pi_fp128le  or be -2.0963761001907e-287
-------------------------------------------------
pi_fp128be[16]
    0x40, 0x00, 0x92, 0x1f, 0xb5, 0x44, 0x42, 0xd1,
    0x84, 0x69, 0x89, 0x8c, 0xc5, 0x17, 0x01, 0xb8
out 0x40 0x00 0x92 0x1f 0xb5 0x44 0x42 0xd1 0x84 0x69 0x89 0x8c 0xc5 0x17 0x01 0xb8 
  pi_fp128be may be 7.2660402568558392281485015532366322e+3199
  pi_fp128be  or be -2.7726117564375e+83
-------------------------------------------------
35 c2 68 21 a2 da 0f c9 00 40 00 00 00 00 00 00 
pi may be 3.1415926535897932385128089594061862e+00
vesta$ 

The recent ( and older r350568 ) r354823 reports the very wrong data
in spite of having flawless perfect little endian fp128 in memory 
representation : 
# 
# uname -apKU
FreeBSD  13.0-CURRENT FreeBSD 13.0-CURRENT #0 r354823: Mon Nov 18 19:49:20 UTC 2019     jenkins@FreeBSD-head-riscv64-build.jail.ci.FreeBSD.org:/tmp/obj/workspace/src/riscv.riscv64/sys/RISCVTEST  riscv riscv64 1300058 1300058
# 
# 
# ./hex_hack.rv64imafdc
-------------------------------------------------------------
        system name = FreeBSD
          node name = 
            release = 13.0-CURRENT
            version = FreeBSD 13.0-CURRENT #0 r354823: Mon Nov 18 19:49:20 UTC 2019     jenkins@FreeBSD-head-riscv64-build.jail.ci.FreeBSD.org:/tmp/obj/workspace/src/riscv.riscv64/sys/RISCVTEST
            machine = riscv
-------------------------------------------------------------
x86_fp80[16]
    0x35, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9,
    0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x35 0xc2 0x68 0x21 0xa2 0xda 0x0f 0xc9 0x00 0x40 0x00 0x00 0x00 0x00 0x00 0x00 
    x86_fp80 may be 4.5565357090895492502716873808281576e-4952
    x86_fp80  or be -8.8796093704934e+43
-------------------------------------------------
pi_fp64le[16]
    0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x18 0x2d 0x44 0x54 0xfb 0x21 0x09 0x40 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
   pi_fp64le may be 1.2844077354038319064254933956786494e-4937
   pi_fp64le  or be    3.1415926535898
-------------------------------------------------
pi_fp64be[16]
    0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
out 0x40 0x09 0x21 0xfb 0x54 0x44 0x2d 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 
   pi_fp64be may be 1.2844077354038319066067654139395456e-4937
   pi_fp64be  or be 3.2073756306764e-192
-------------------------------------------------
pi_fp128le[16]
    0xb8, 0x01, 0x17, 0xc5, 0x8c, 0x89, 0x69, 0x84,
    0xd1, 0x42, 0x44, 0xb5, 0x1f, 0x92, 0x00, 0x40
out 0xb8 0x01 0x17 0xc5 0x8c 0x89 0x69 0x84 0xd1 0x42 0x44 0xb5 0x1f 0x92 0x00 0x40 
  pi_fp128le may be 2.0000076405016834831430856216761921e+00
  pi_fp128le  or be -2.0963761001907e-287
-------------------------------------------------
pi_fp128be[16]
    0x40, 0x00, 0x92, 0x1f, 0xb5, 0x44, 0x42, 0xd1,
    0x84, 0x69, 0x89, 0x8c, 0xc5, 0x17, 0x01, 0xb8
out 0x40 0x00 0x92 0x1f 0xb5 0x44 0x42 0xd1 0x84 0x69 0x89 0x8c 0xc5 0x17 0x01 0xb8 
  pi_fp128be may be -1.2377431474242674717718477250561708e-616
  pi_fp128be  or be -2.7726117564375e+83
-------------------------------------------------
b8 01 17 c5 8c 89 69 84 d1 42 44 b5 1f 92 00 40 
pi may be 2.0000076405016834831430856216761921e+00
# 

I checked the assembly and the static data given to the assembler is
bit for bit perfect : 

rv64g$ cat hex_hack.s
        .file   "hex_hack.c"
        .option nopic
        .text
        .align  1
        .type   uname, @function
uname:
        addi    sp,sp,-32
        sd      ra,24(sp)
        sd      s0,16(sp)
        addi    s0,sp,32
        sd      a0,-24(s0)
        ld      a1,-24(s0)
        li      a0,256
        call    __xuname
        mv      a5,a0
        mv      a0,a5
        ld      ra,24(sp)
        ld      s0,16(sp)
        addi    sp,sp,32
        jr      ra
        .size   uname, .-uname
        .section        .rodata
        .align  3
.LC6:
        .string "C"
        .align  3
.
.
.
.LC46:
        .string "pi may be %38.34Le\n"
        .align  3
.
.
.
main:
        addi    sp,sp,-1424
        sd      ra,1416(sp)
        sd      s0,1408(sp)
        addi    s0,sp,1424
        mv      a5,a0
        sd      a1,-1424(s0)
        sw      a5,-1412(s0)
        lui     a5,%hi(.LC5)
        ld      a4,%lo(.LC5)(a5)
        sd      a4,-48(s0)
        ld      a5,%lo(.LC5+8)(a5)
        sd      a5,-40(s0)
        lui     a5,%hi(.LC6)
        addi    a1,a5,%lo(.LC6)
        li      a0,6
        call    setlocale
        addi    a5,s0,-1328
        mv      a0,a5
        call    uname
.
.
.
.
.L16:
        lw      a5,-20(s0)
        mv      a4,a5
        li      a5,15
        bleu    a4,a5,.L17
        lui     a5,%hi(.LC17)
        addi    a0,a5,%lo(.LC17)
        call    printf
        ld      a5,-48(s0)
        ld      a6,-40(s0)
        mv      a2,a5
        mv      a3,a6
        lui     a5,%hi(.LC46)
        addi    a0,a5,%lo(.LC46)
        call    printf
        li      a5,0
        mv      a0,a5
        ld      ra,1416(sp)
        ld      s0,1408(sp)
        addi    sp,sp,1424
        jr      ra
        .size   main, .-main
        .section        .rodata
        .align  4
.LC5:
        .word   3306619320
        .word   2221509004
        .word   3041149649
        .word   1073779231
        .ident  "GCC: (GNU) 8.2.0"
rv64g$ 

The static data at LC5 is correct thus : 

rv64g$ echo '16o 1073779231p 3041149649p 2221509004p 3306619320pq' | dc 
4000921F
B54442D1
8469898C
C51701B8
rv64g$ 

However the output from printf("pi may be %38.34Le\n", pi) is clearly
wrong. 



-- 
Dennis Clarke
RISC-V/SPARC/PPC/ARM/CISC
UNIX and Linux spoken
GreyBeard and suspenders optional
Comment 1 Dennis Clarke 2019-11-19 03:15:47 UTC
Modify bug arch to riscv.
Comment 2 Dennis Clarke 2019-11-19 03:18:34 UTC
Created attachment 209240 [details]
Assemble , compile and link and check results.
Comment 3 Kubilay Kocak freebsd_committer freebsd_triage 2019-11-19 06:30:58 UTC
Thank you for the report Dennis

Could you:

- Summarise the specific expected vs actual output
- Clarify/confirm whether or not this is a regression (post base r351523 ppc64 /  / base r350568 riscv / base r354823 jenkins) and 
- If a regression, the latest revision that *didn't* exhibit the issue. Bisection here would be perfect, if possible.
Comment 4 Dennis Clarke 2019-11-19 13:24:10 UTC
(In reply to Kubilay Kocak from comment #3)

The output should be the valid IEEE754-2008 floating point
representation for pi exactly the same as the Solaris 10 sparcv9
server does : 

    ( 1 ) expected output should be in the last lines :

b8 01 17 c5 8c 89 69 84 d1 42 44 b5 1f 92 00 40
pi may be 3.1415926535897932384626433832795028e+00


          That would be precisely correct for a little endian RISC-V
          architecture. 


    ( 2 ) actual output is very correct in memory and very wrong
          printf behavior : 

b8 01 17 c5 8c 89 69 84 d1 42 44 b5 1f 92 00 40 
pi may be 2.0000076405016834831430856216761921e+00
# 

So I don't think that pi is that close to 2.00000764...  :)

The other question is have I ever seen this work ?  The answer is no.
Sadly I have never seen this work correctly. 

The output here suggests that the printf() routine correctly handles
the static format string seen in the assembly listing at LC46 in that
we do get the correct number of ascii digits in the correct places
however the in memory little endian fp128 data is not handled well.

The text [1]"Handbook of Floating-Point Arithmetic", 2nd Ed, pg48,
by Muller, J.-M., Brunie, N., de Dinechin, F., Jeannerod, C.-P.,
Joldes, M., Lefèvre, V., Melquiond, G., Revol, N., Torres, S.  states
that the 128 bit floating point format should have a single sign bit,
a set of 15 exponent bits and then a mantissa or significand of 112 bits
wherein there is an implied leading "1" bit for an effective 113 bit
significand.  The IEEE 754-1985 standard did not define this format 
whereas the [2]IEEE 754-2008 standard does.  This is well implemented
in Solaris and OpenSolaris as well as on IBM Power9 systems running
Red Hat Enterprise Linux. 

I have single stepped through the relevant lines of the code on an IBM
Power system and I think the issue is with /lib/libc/stdio/vfprintf.c
where the in memory data is handled wrongly. 

I have a theory on why we are seeing a value near 2.0 but have to work
on that yet.

[1] https://www.springer.com/gp/book/9783319765259
[2] IEEE Computer Society.  IEEE Standard for Floating-Point Arithmetic.
    IEEE Standard 754-2008, August 2008. also ISBN: 978-0-7381-5752-8 
    https://ieeexplore.ieee.org/document/4610935
Comment 5 Dennis Clarke 2019-11-19 13:26:37 UTC
The output from the Solaris 10 sparcv9 server is clearly to be
big endian however for claity I simply want to point out that
the RISC-V architecture is little endian and that the in memory
data is precisely correct. Regardless we should never see a 
value of pi as 2.0000...
Comment 6 Dennis Clarke 2019-11-26 18:21:08 UTC
Merely a follow up here to indicate this problem has been around since
at least r350568 : 

root@callisto:/home/dclarke/foo # uname -apKU
FreeBSD callisto 13.0-CURRENT FreeBSD 13.0-CURRENT r350568 QEMU  riscv riscv64 1300038 1300038
root@callisto:/home/dclarke/foo # 
root@callisto:/home/dclarke/foo # cat pi.c

/*************************************************
 * The Open Group Base Specifications Issue 6
 * IEEE Std 1003.1, 2004 Edition
 *************************************************/
#define _XOPEN_SOURCE 600

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

int main ( int argc, char *argv[])
{

    long double pi128 = 3.1415926535897932384626433832795028841971693993751L;
    double pi64 = M_PI;

    printf (" the sizeof(pi128) is %i\n", sizeof(pi128) );
    printf (" the sizeof(pi64) is %i\n", sizeof(pi64) );

    printf ("pi128 may be %44.38Lg\n", pi128 );
    printf ("pi64 may be %18.16g\n", pi64 );

    return ( EXIT_SUCCESS );

}

root@callisto:/home/dclarke/foo # 
root@callisto:/home/dclarke/foo # cat  pi.s
        .file   "pi.c"
        .option nopic
        .text
        .section        .rodata
        .align  3
.LC2:
        .string " the sizeof(pi128) is %i\n"
        .align  3
.LC3:
        .string " the sizeof(pi64) is %i\n"
        .align  3
.LC4:
        .string "pi128 may be %44.38Lg\n"
        .align  3
.LC5:
        .string "pi64 may be %44.38Lg\n"
        .text
        .align  1
        .globl  main
        .type   main, @function
main:
        addi    sp,sp,-64
        sd      ra,56(sp)
        sd      s0,48(sp)
        addi    s0,sp,64
        mv      a5,a0
        sd      a1,-64(s0)
        sw      a5,-52(s0)
        lui     a5,%hi(.LC0)
        ld      a4,%lo(.LC0)(a5)
        sd      a4,-32(s0)
        ld      a5,%lo(.LC0+8)(a5)
        sd      a5,-24(s0)
        lui     a5,%hi(.LC1)
        fld     fa5,%lo(.LC1)(a5)
        fsd     fa5,-40(s0)
        li      a1,16
        lui     a5,%hi(.LC2)
        addi    a0,a5,%lo(.LC2)
        call    printf
        li      a1,8
        lui     a5,%hi(.LC3)
        addi    a0,a5,%lo(.LC3)
        call    printf
        ld      a2,-32(s0)
        ld      a3,-24(s0)
        lui     a5,%hi(.LC4)
        addi    a0,a5,%lo(.LC4)
        call    printf
        ld      a1,-40(s0)
        lui     a5,%hi(.LC5)
        addi    a0,a5,%lo(.LC5)
        call    printf
        li      a5,0
        mv      a0,a5
        ld      ra,56(sp)
        ld      s0,48(sp)
        addi    sp,sp,64
        jr      ra
        .size   main, .-main
        .section        .rodata
        .align  4
.LC0:
        .word   3306619320
        .word   2221509004
        .word   3041149649
        .word   1073779231
        .align  3
.LC1:
        .word   1413754136
        .word   1074340347
        .ident  "GCC: (GNU) 8.2.0"
root@callisto:/home/dclarke/foo # 
root@callisto:/home/dclarke/foo # 
root@callisto:/home/dclarke/foo # ./pi
 the sizeof(pi128) is 16
 the sizeof(pi64) is 8
pi128 may be      2.0000076293945362811600603241536472604
pi64 may be  3.141592653589793
root@callisto:/home/dclarke/foo # 

root@callisto:/home/dclarke/foo # echo "16o 1074340347p 1413754136pq" | dc
400921FB
54442D18
root@callisto:/home/dclarke/foo # echo "16o 1073779231p 3041149649p 2221509004p 3306619320pq"  | dc 
4000921F
B54442D1
8469898C
C51701B8
root@callisto:/home/dclarke/foo # 

So that is perfect in memory and wrong in output. 


-- 
Dennis Clarke
RISC-V/SPARC/PPC/ARM/CISC
UNIX and Linux spoken
GreyBeard and suspenders optional
Comment 7 Dennis Clarke 2019-11-28 20:41:54 UTC
Yep, we have a problem in FreeBSD 13.0-CURRENT r355009 perhaps
in _ldtoa.c still and I think maybe the real issue is with 

    head/lib/libc/gdtoa/machdep_ldisQ.c

where we see 


/*
 * Machine-dependent glue to integrate David Gay's gdtoa
 * package into libc for architectures where a long double
 * uses quad precision, such as sparc64.
 */


Well bingo ... other than the endianess we have the same data
in memory and confusion in the printf output. 

So still digging.


-- 
Dennis Clarke
RISC-V/SPARC/PPC/ARM/CISC
UNIX and Linux spoken
GreyBeard and suspenders optional
Comment 8 Mitchell Horne freebsd_committer freebsd_triage 2020-06-23 20:38:37 UTC
Hi Dennis,

Thanks for the detailed report. I was finally able to find the source of the issue: GCC used to generate 64-bit long doubles and the workaround for that was still enabled.

I've posted a patch addressing the issue here: https://reviews.freebsd.org/D25420

The test program gives the expected output for me, but if you'd like to verify the fix at well it would be helpful.
Comment 9 commit-hook freebsd_committer freebsd_triage 2020-06-29 19:31:24 UTC
A commit references this bug:

Author: mhorne
Date: Mon Jun 29 19:30:35 UTC 2020
New revision: 362788
URL: https://svnweb.freebsd.org/changeset/base/362788

Log:
  Fix printf(3) output of long doubles on RISC-V

  When the RISC-V port was initially committed to FreeBSD, GCC would
  generate 64-bit long doubles, and the definitions in _fpmath.h reflected
  that. This was changed to 128-bit in GCC later that year [1], but the
  definitions were never updated, despite the documented workaround. This
  causes printf(3) and friends to interpret only the low 64-bits of a long
  double in ldtoa, thereby printing incorrect values.

  Update the definitions now that both clang and GCC generate 128-bit long
  doubles.

  [1] https://github.com/riscv/riscv-gcc/commit/54b21fc5ae83cefec44bc2caed4a8c664c274ba0

  PR:		242067
  Reported by:	Dennis Clarke <dclarke@blastwave.org>
  MFC after:	1 week
  Differential Revision:	https://reviews.freebsd.org/D25420

Changes:
  head/lib/libc/riscv/_fpmath.h
Comment 10 commit-hook freebsd_committer freebsd_triage 2020-07-06 15:00:52 UTC
A commit references this bug:

Author: mhorne
Date: Mon Jul  6 15:00:29 UTC 2020
New revision: 362964
URL: https://svnweb.freebsd.org/changeset/base/362964

Log:
  MFC r362788:

  Fix printf(3) output of long doubles on RISC-V

  PR:	242067

Changes:
  stable/12/lib/libc/riscv/_fpmath.h